﻿#region Copyright (c) 2000-2008 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{       AgDataGrid                                 }
{                                                                   }
{       Copyright (c) 2000-2008 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2008 Developer Express Inc.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using DevExpress.AgDataGrid.Data;
using DevExpress.AgDataGrid.Internal;
using System.Windows.Controls.Primitives;
using System.Collections.Generic;
using DevExpress.AgDataGrid.Data.Helpers;
using System.Text;
using System.Collections.Specialized;
using System.Windows.Markup;
using System.Windows.Browser;
using DevExpress.AgDataGrid.UIAutomation;
namespace DevExpress.AgDataGrid {
	public enum DataPreviewVisibility { Collapsed = 0, ForFocusedRow = 1, ForAllRows = 2 };
	public enum DataGridSelectionMode { None, MultiSelection }
	[TemplatePart(Name = AgDataGrid.DATAGRID_elementSurfaceName, Type = typeof(Canvas))]
	[TemplatePart(Name = AgDataGrid.DATAGRID_elementGridMainClipName, Type = typeof(RectangleGeometry))]
	[TemplatePart(Name = AgDataGrid.DATAGRID_elementRootName, Type = typeof(Grid))]
	[TemplatePart(Name = AgDataGrid.DATAGRID_elementCellsName, Type = typeof(Panel))]
	[TemplatePart(Name = AgDataGrid.DATAGRID_elementCellsClipperName, Type = typeof(Canvas))]
	[TemplatePart(Name = AgDataGrid.DATAGRID_elementCellsBorderName, Type = typeof(UIElement))]
	[TemplatePart(Name = AgDataGrid.DATAGRID_elementColumnHeadersName, Type = typeof(Panel))]
	[TemplatePart(Name = AgDataGrid.DATAGRID_elementTotalPanelName, Type = typeof(Panel))]
	[TemplatePart(Name = AgDataGrid.DATAGRID_elementGroupPanelName, Type = typeof(Panel))]
	[TemplatePart(Name = AgDataGrid.DATAGRID_elementVerticalScrollbarName, Type = typeof(ScrollBar))]
	[TemplatePart(Name = AgDataGrid.DATAGRID_elementHorizontalScrollbarName, Type = typeof(ScrollBar))]
	[TemplatePart(Name = AgDataGrid.DATAGRID_elementBottomRightCornerName, Type = typeof(UIElement))]
	public partial class AgDataGrid : Control, IAgDataGridRowOwner, IGroupPanelDropElementOwner,
									IAgDataGridColumnOwner, IAgDataGridSummaryOwner, IDataControllerVisualClient,
									IScrollOnDragging, IColumnsAutoWidth, ICommandGrid, IRowsControllerOwner {
		const string DATAGRID_elementSurfaceName = "Surface";
		const string DATAGRID_elementGridMainClipName = "GridMainClip";
		const string DATAGRID_elementRootName = "RootElement";
		const string DATAGRID_elementCellsName = "CellsPresenterElement";
		const string DATAGRID_elementCellsClipperName = "CellsClipperElement";
		const string DATAGRID_elementCellsBorderName = "CellsBorder";
		const string DATAGRID_elementColumnHeadersName = "ColumnHeadersPresenterElement";
		const string DATAGRID_elementTotalPanelName = "TotalPanelPresenterElement";
		const string DATAGRID_elementGroupPanelName = "GroupPanelPresenterElement";
		const string DATAGRID_elementVerticalScrollbarName = "VerticalScrollbarElement";
		const string DATAGRID_elementHorizontalScrollbarName = "HorizontalScrollbarElement";
		const string DATAGRID_elementBottomRightCornerName = "BottomRightCornerElement";
		const string DATAGRID_elementHeaderDraggingThumb = "HeaderDraggingThumb";
		const string DATAGRID_elementLeftBorderName = "LeftBorder";
		const string CurrentCellFocusVisualNormalName = "Normal State";
		const string CurrentCellFocusVisualUnfocusedName = "Unfocused State";
		public const double DefaultColumnWidth = 100;
		public const double DefaultRowHeight = 29;
		public const double DefaultColumnMinWidth = 22;
		public const double DefaultStartDragShift = 3;
		public const int HorisontalScrollSpeed = 100;
		public const double HorisontalScrollStartShift = 22;
		public const double DefaultLevelIndent = 22;
		public const double DefaultWidth = 400;
		public const double DefaultHeight = 300;
		public const double ScrollAreaSegmentCount = 5;
		public const double ScrollAreaOffset = 10;
		public const double ScrollAreaWidth = 30;
		public const double ScrollFactor = 4;
		public event PreviewStatusEventHandler PreviewStatus;
		public event CustomSummaryEventHandler CustomSummary;
		public event CustomSummaryExistEventHandler CustomSummaryExists;
		public event RowDeletingEventHandler RowDeleting;
		public event RowDeletedEventHandler RowDeleted;
		public event RowEditingEventHandler RowEditing;
		public event RowEditedEventHandler RowEdited;
		public event DevExpress.AgDataGrid.Data.SelectionChangedEventHandler SelectionChanged;
		public event FocusedRowChangingEventHandler FocusedRowChanging;
		public event FocusedRowChangedEventHandler FocusedRowChanged;
		public event MouseOverRowEventHandler MouseOverRowChanged;
		public static readonly DependencyProperty AutoGenerateColumnsProperty = DependencyProperty.Register("AutoGenerateColumns", typeof(bool), typeof(AgDataGrid), new PropertyMetadata(OnAutoGenerateColumnsPropertyChanged));
		public static readonly DependencyProperty FocusedRowHandleProperty = DependencyProperty.Register("FocusedRowHandle",
				typeof(int), typeof(AgDataGrid), new PropertyMetadata(OnFocusedRowHandlePropertyChanged));
		public static readonly DependencyProperty DataSourceProperty = DependencyProperty.Register("DataSource",
				typeof(object), typeof(AgDataGrid), new PropertyMetadata(OnDataSourcePropertyChanged));
		public static readonly DependencyProperty PreviewTemplateProperty = DependencyProperty.Register("PreviewTemplate",
				typeof(DataTemplate), typeof(AgDataGrid), new PropertyMetadata(OnPreviewTemplatePropertyChanged));
		public static readonly DependencyProperty ShowVerticalLinesProperty = DependencyProperty.Register("ShowVerticalLines",
				typeof(bool), typeof(AgDataGrid), new PropertyMetadata(OnShowLinesPropertyChanged));
		public static readonly DependencyProperty RowVerticalLinesBrushProperty = DependencyProperty.Register("RowVerticalLinesBrush",
				typeof(Brush), typeof(AgDataGrid), new PropertyMetadata(OnShowLinesPropertyChanged));
		public static readonly DependencyProperty ShowHorizontalLinesProperty = DependencyProperty.Register("ShowHorizontalLines",
				typeof(bool), typeof(AgDataGrid), new PropertyMetadata(OnShowLinesPropertyChanged));
		public static readonly DependencyProperty VerticalLinesThicknessProperty = DependencyProperty.Register("VerticalLinesThickness",
				typeof(double), typeof(AgDataGrid), new PropertyMetadata(OnLinesThicknessPropertyChanged));
		public static readonly DependencyProperty HorizontalLinesThicknessProperty = DependencyProperty.Register("HorizontalLinesThickness",
				typeof(double), typeof(AgDataGrid), new PropertyMetadata(OnLinesThicknessPropertyChanged));
		public static readonly DependencyProperty CellStyleProperty = DependencyProperty.Register("CellStyle",
				typeof(AgStyle), typeof(AgDataGrid), new PropertyMetadata(OnCellStylePropertyChanged));
		public static readonly DependencyProperty FocusedCellStyleProperty = DependencyProperty.Register("FocusedCellStyle",
				typeof(AgStyle), typeof(AgDataGrid), new PropertyMetadata(OnCellStylePropertyChanged));
		public static readonly DependencyProperty EditingCellStyleProperty = DependencyProperty.Register("EditingCellStyle",
				typeof(AgStyle), typeof(AgDataGrid), new PropertyMetadata(OnCellStylePropertyChanged));
		public static readonly DependencyProperty FocusedRowCellStyleProperty = DependencyProperty.Register("FocusedRowCellStyle",
			typeof(AgStyle), typeof(AgDataGrid), new PropertyMetadata(OnCellStylePropertyChanged));
		public static readonly DependencyProperty ColumnHeaderStyleProperty = DependencyProperty.Register("ColumnHeaderStyle",
				typeof(Style), typeof(AgDataGrid), new PropertyMetadata(OnColumnHeaderStylePropertyChanged));
		public static readonly DependencyProperty MouseOverColumnHeaderStyleProperty = DependencyProperty.Register("MouseOverColumnHeaderStyle",
				typeof(Style), typeof(AgDataGrid), new PropertyMetadata(OnColumnHeaderStylePropertyChanged));
		public static readonly DependencyProperty PressedColumnHeaderStyleProperty = DependencyProperty.Register("PressedColumnHeaderStyle",
				typeof(Style), typeof(AgDataGrid), new PropertyMetadata(OnColumnHeaderStylePropertyChanged));
		public static readonly DependencyProperty DragArrowsTemplateProperty = DependencyProperty.Register("DragArrowsTemplate",
			typeof(DataTemplate), typeof(AgDataGrid), new PropertyMetadata(OnDragArrowsTemplatePropertyChanged));
		public static readonly DependencyProperty PreviewVisibilityProperty = DependencyProperty.Register("PreviewVisibility",
				typeof(DataPreviewVisibility), typeof(AgDataGrid), new PropertyMetadata(OnPreviewTemplatePropertyChanged));
		public static readonly DependencyProperty DataRowTemplateProperty = DependencyProperty.Register("DataRowTemplate",
				typeof(ControlTemplate), typeof(AgDataGrid), new PropertyMetadata(OnDataRowTemplatePropertyChanged));
		public static readonly DependencyProperty EmptyGroupPanelTemplateProperty = DependencyProperty.Register("EmptyGroupPanelTemplate",
				typeof(DataTemplate), typeof(AgDataGrid), new PropertyMetadata(OnEmptyGroupPanelTemplatePropertyChanged));
		public static readonly DependencyProperty TotalCellStyleProperty = DependencyProperty.Register("TotalCellStyle", typeof(Style), typeof(AgDataGrid),
			new PropertyMetadata((d, e) => ((AgDataGrid)d).PropertyChangedTotalCellStyle()));
		public static readonly DependencyProperty ShowTotalsProperty = DependencyProperty.Register("ShowTotals",
				typeof(Visibility), typeof(AgDataGrid), new PropertyMetadata(OnShowHidePropertyChanged));
		public static readonly DependencyProperty ShowGroupPanelProperty = DependencyProperty.Register("ShowGroupPanel",
				typeof(Visibility), typeof(AgDataGrid), new PropertyMetadata(OnShowHidePropertyChanged));
		public static readonly DependencyProperty ShowColumnHeadersProperty = DependencyProperty.Register("ShowColumnHeaders",
				typeof(Visibility), typeof(AgDataGrid), new PropertyMetadata(OnShowHidePropertyChanged));
		public static readonly DependencyProperty DelayScrollingProperty = DependencyProperty.Register("DelayScrolling",
						typeof(bool), typeof(AgDataGrid), new PropertyMetadata(OnDelayScrollingPropertyChanged));
		static void OnDelayScrollingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			if (d.IsHandlerSuspended(DelayScrollingProperty)) return;
			AgDataGrid grid = d as AgDataGrid;
			if (grid != null) {
				grid.OnDelayScrollingChanged(true);
			}
		}
		void OnDelayScrollingChanged(bool p) {
		}
		static void OnAutoGenerateColumnsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			if (d.IsHandlerSuspended(AutoGenerateColumnsProperty)) return;
			AgDataGrid grid = d as AgDataGrid;
			if (grid != null) {
				grid.OnAutoGenerateColumnsChanged(true);
			}
		}
		static void OnShowHidePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			if (d.IsHandlerSuspended(EmptyGroupPanelTemplateProperty)) return;
			AgDataGrid grid = d as AgDataGrid;
			if (grid != null) {
				grid.SetValueNoCallback(e.Property, e.NewValue);
				grid.OnShowHideChanged();
			}
		}
		static void OnEmptyGroupPanelTemplatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			if (d.IsHandlerSuspended(EmptyGroupPanelTemplateProperty)) return;
			AgDataGrid grid = d as AgDataGrid;
			if (grid != null) {
				grid.OnEmptyGroupPanelTemplateChanged((DataTemplate)e.NewValue, (DataTemplate)e.OldValue);
			}
		}
		static void OnFocusedRowHandlePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			if (d.IsHandlerSuspended(FocusedRowHandleProperty)) return;
			AgDataGrid grid = d as AgDataGrid;
			if (grid == null) return;
			grid.OnFocusedRowHandleChanged((int)e.NewValue, (int)e.OldValue);
		}
		static void OnDataSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			if (d.IsHandlerSuspended(DataSourceProperty)) return;
			AgDataGrid grid = d as AgDataGrid;
			if (grid == null) return;
			grid.OnDataSourceChanged(e.NewValue, e.OldValue);
		}
		static void OnDataRowTemplatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			AgDataGrid grid = d as AgDataGrid;
			if (grid != null) {
				grid.OnPreviewTemplateChanged();
			}
		}
		static void OnPreviewTemplatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			AgDataGrid grid = d as AgDataGrid;
			if (grid != null) {
				grid.OnPreviewTemplateChanged();
			}
		}
		static void OnShowLinesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			if (d.IsHandlerSuspended(ShowHorizontalLinesProperty) || d.IsHandlerSuspended(ShowVerticalLinesProperty)) return;
			AgDataGrid grid = d as AgDataGrid;
			if (grid == null) return;
			grid.OnShowLinesChanged();
		}
		static void OnLinesThicknessPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			if (d.IsHandlerSuspended(HorizontalLinesThicknessProperty) || d.IsHandlerSuspended(VerticalLinesThicknessProperty)) return;
			AgDataGrid grid = d as AgDataGrid;
			if (grid == null) return;
			grid.OnLinesThicknessChanged();
		}
		static void OnCellStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			if (d.IsHandlerSuspended(CellStyleProperty) || d.IsHandlerSuspended(FocusedCellStyleProperty) ||
				d.IsHandlerSuspended(FocusedRowCellStyleProperty)) return;
			AgDataGrid grid = d as AgDataGrid;
			if (grid == null) return;
			grid.OnCellStyleChanged();
		}
		static void OnColumnHeaderStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			if (d.IsHandlerSuspended(ColumnHeaderStyleProperty)) return;
			AgDataGrid grid = d as AgDataGrid;
			if (grid == null) return;
			grid.OnColumnHeaderStyleChanged();
		}
		static void OnDragArrowsTemplatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			if (d.IsHandlerSuspended(DragArrowsTemplateProperty)) return;
			AgDataGrid grid = d as AgDataGrid;
			if (grid == null) return;
			grid.OnDragArrowsTemplateChanged();
		}
		protected virtual void PropertyChangedTotalCellStyle() {
			if (!this.IsHandlerSuspended(TotalCellStyleProperty)) {
				foreach (IAgDataGridTotalCellOwner column in Columns)
					column.TotalCellStyleChanged();
				UpdateChildren();
			}
		}
		AgDataGridColumnCollection columns;
		List<AgDataGridColumn> sortedColumns;
		ReadOnlyCollection<AgDataGridColumn> visibleColumns;
		ObservableCollection<AgDataGridSummaryItem> totals;
		AgDataGridColumn changedVisibilityColumn;
		Canvas surface;
		Grid root;
		Panel headersPanel;
		AgLineStackPanel lineHeadersPanel;
		Panel totalPanel;
		Panel groupPanel;
		Canvas dataPanelClipper;
		UIElement dataPanelBorder;
		Panel dataPanel;
		ScrollBar verticalScrollBar;
		ScrollBar horizontalScrollBar;
		FrameworkElement bottomRightCorner;
		Selection selection;
		FrameworkElement dragArrows;
		DataController dataController;
		RowsController rowsController;
		int focusedColumnIndex;
		int mouseOverRowHandle;
		bool isTemplateLoaded;
		bool isLoaded;
		bool columnsAutoWidth;
		bool changeOddRowsAppearance;
		double prevActualWidth;
		double prevActualHeight;
		public AgDataGrid() {
			DefaultStyleKey = typeof(AgDataGrid);
			this.prevActualWidth = Double.NaN;
			this.prevActualHeight = Double.NaN;
			Loaded += new RoutedEventHandler(OnLoaded);
			this.dataController = CreateDataController();
			DataController.VisualClient = this;
			this.rowsController = CreateRowsController();
			this.columns = new AgDataGridColumnCollection();
			Columns.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(OnColumnsCollectionChanged);
			Columns.BeforeCollectionChanged += new AgDataGridObservableCollectionBeforeCollectionChangedEventHandler(OnColumnsBeforeCollectionChanged);
			this.sortedColumns = new List<AgDataGridColumn>();
			this.SetValueNoCallback(FocusedRowHandleProperty, DataController.FocusedControllerRowIndex);
			this.SetValueNoCallback(AutoGenerateColumnsProperty, true);
			this.SetValueNoCallback(ShowHorizontalLinesProperty, true);
			this.SetValueNoCallback(ShowVerticalLinesProperty, true);
			this.focusedColumnIndex = -1;
			this.mouseOverRowHandle = DataController.InvalidRow;
			this.selection = new Selection(DataController);
			this.TabNavigation = KeyboardNavigationMode.Once;
			this.IsTabStop = true;
			this.KeyDown += new KeyEventHandler(OnKeyDown);
			this.KeyUp += new KeyEventHandler(OnKeyUp);
			this.GotFocus += new RoutedEventHandler(OnGotFocus);
			this.LostFocus += new RoutedEventHandler(OnLostFocus);
			this.MouseLeftButtonDown += new MouseButtonEventHandler(DataGrid_MouseLeftButtonDown);
			this.MouseMove += new MouseEventHandler(DataGrid_MouseMove);
			this.MouseLeave += new MouseEventHandler(AgDataGrid_MouseLeave);
			this.MouseEnter += new MouseEventHandler(AgDataGrid_MouseEnter);
			this.LayoutUpdated += new EventHandler(AgDataGrid_LayoutUpdated);
			Totals.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(totals_CollectionChanged);
			MouseHelper.SetMouseWheelHandler(DoVerticalScrollChange);
			this.SetValueNoCallback(VerticalLinesThicknessProperty, 1.0);
			this.SetValueNoCallback(HorizontalLinesThicknessProperty, 1.0);
			this.SetValueNoCallback(ShowTotalsProperty, Visibility.Collapsed);
			this.SetValueNoCallback(ShowGroupPanelProperty, Visibility.Collapsed);
			this.SetValueNoCallback(ShowColumnHeadersProperty, Visibility.Visible);
			this.SetValueNoCallback(PreviewVisibilityProperty, DataPreviewVisibility.ForFocusedRow);
			IsMouseInControl = false;
		}
		RowsController CreateRowsController() {
			return new RowsController(this);
		}
		#region ColumnProperties
		bool allowColumnSorting = true;
		bool allowColumnGrouping = true;
		bool allowColumnResizing = true;
		bool allowColumnMoving = true;
		public bool AllowColumnSorting { get { return allowColumnSorting; } set { allowColumnSorting = value; } }
		public bool AllowColumnGrouping { get { return allowColumnGrouping; } set { allowColumnGrouping = value; } }
		public bool AllowColumnMoving { get { return allowColumnMoving; } set { allowColumnMoving = value; } }
		public bool AllowColumnResizing {
			get { return allowColumnResizing; }
			set {
				if (allowColumnResizing == value) return;
				allowColumnResizing = value;
				UpdateChildren();
			}
		}
		#endregion
		#region EditingProperties
		bool allowEditing = true;
		bool allowDeleting = true;
		public bool AllowEditing { get { return allowEditing; } set { allowEditing = value; } }
		public bool AllowDeleting { get { return allowDeleting; } set { allowDeleting = value; } }
		#endregion
		#region CommonProperties
		DataGridSelectionMode selectionMode = DataGridSelectionMode.None;
		public DataGridSelectionMode SelectionMode {
			get { return selectionMode; }
			set {
				if (SelectionMode == value) return;
				selectionMode = value;
				OnSelectionModeChanged();
			}
		}
		protected virtual void OnSelectionModeChanged() {
			if (SelectionMode == DataGridSelectionMode.None) {
				Selection.ClearSelected();
			}
		}
		#endregion
		public RowsController RowsController { get { return rowsController; } }
		public ControlTemplate DataRowTemplate { get { return (ControlTemplate)GetValue(DataRowTemplateProperty); } set { SetValue(DataRowTemplateProperty, value); } }
		public Brush RowVerticalLinesBrush { get { return (Brush)GetValue(RowVerticalLinesBrushProperty); } set { SetValue(RowVerticalLinesBrushProperty, value); } }
		public double VerticalLinesThickness { get { return (double)GetValue(VerticalLinesThicknessProperty); } set { SetValue(VerticalLinesThicknessProperty, value); } }
		public double HorizontalLinesThickness { get { return (double)GetValue(HorizontalLinesThicknessProperty); } set { SetValue(HorizontalLinesThicknessProperty, value); } }
		public DataPreviewVisibility PreviewVisibility { get { return (DataPreviewVisibility)GetValue(PreviewVisibilityProperty); } set { SetValue(PreviewVisibilityProperty, value); } }
		public DataTemplate EmptyGroupPanelTemplate { get { return (DataTemplate)GetValue(EmptyGroupPanelTemplateProperty); } set { SetValue(EmptyGroupPanelTemplateProperty, value); } }
		private bool IsMouseInControl { get; set; }
		public void DoVerticalScrollChange(object sender, MouseWheelHandlerEventArgs args) {
			if (!IsMouseInControl) return;
			if (Parent == null) return;
			if (VerticalScrollBar != null) {
				VerticalScrollBar.Value -= args.Delta;
				PerformLayout();
			}
		}
		protected bool IsPreviewAnimationBlocked { get; set; }
		protected Size DefaultSize { get { return new Size(DefaultWidth, DefaultHeight); } }
		protected virtual bool IsTemplateLoaded {
			get { return isTemplateLoaded; }
			set {
				if (isTemplateLoaded == value) return;
				isTemplateLoaded = value;
				if (value) OnTemplateLoaded();
			}
		}
		public bool IsLoaded { get { return isLoaded; } }
		public object DataSource {
			get { return GetValue(DataSourceProperty); }
			set { SetValue(DataSourceProperty, value); }
		}
		public bool DelayScrolling { get { return (bool)GetValue(DelayScrollingProperty); } set { SetValue(DelayScrollingProperty, value); } }
		public Visibility ShowColumnHeadersTopLine { get { return (ShowColumnHeaders == Visibility.Visible && ShowGroupPanel == Visibility.Visible) ? Visibility.Visible : Visibility.Collapsed; } }
		public Visibility ShowTopBorder { get { return (ShowColumnHeaders != Visibility.Visible && ShowGroupPanel != Visibility.Visible) ? Visibility.Visible : Visibility.Collapsed; } }
		public Visibility ShowTotals { get { return (Visibility)GetValue(ShowTotalsProperty); } set { SetValue(ShowTotalsProperty, value); } }
		public Visibility ShowGroupPanel { get { return (Visibility)GetValue(ShowGroupPanelProperty); } set { SetValue(ShowGroupPanelProperty, value); } }
		public Visibility ShowColumnHeaders { get { return (Visibility)GetValue(ShowColumnHeadersProperty); } set { SetValue(ShowColumnHeadersProperty, value); } }
		public bool ShowVerticalLines { get { return (bool)GetValue(ShowVerticalLinesProperty); } set { SetValue(ShowVerticalLinesProperty, value); } }
		public bool ShowHorizontalLines { get { return (bool)GetValue(ShowHorizontalLinesProperty); } set { SetValue(ShowHorizontalLinesProperty, value); } }
		public Selection Selection { get { return selection; } }
		public AgDataGridColumnCollection Columns { get { return columns; } }
		public DataTemplate DragArrowsTemplate {
			get { return (DataTemplate)GetValue(DragArrowsTemplateProperty); }
			set { SetValue(DragArrowsTemplateProperty, value); }
		}
		protected FrameworkElement DragArrows {
			get {
				if (DragArrowsTemplate == null) return null;
				if (dragArrows == null) {
					dragArrows = DragArrowsTemplate.LoadContent() as FrameworkElement;
					if (dragArrows == null)
						throw new ArgumentException("The DragArrowsTemplate should return a FrameworkElement object!");
				}
				return dragArrows;
			}
		}
		public ReadOnlyCollection<AgDataGridColumn> VisibleColumns {
			get {
				if (visibleColumns == null) {
					BuildVisibleColumns();
				}
				return visibleColumns;
			}
		}
		public ObservableCollection<AgDataGridSummaryItem> Totals { get { return totals ?? (totals = CreateTotalsCollection()); } }
		public DataTemplate PreviewTemplate {
			get { return GetValue(PreviewTemplateProperty) as DataTemplate; }
			set { SetValue(PreviewTemplateProperty, value); }
		}
		ObservableCollection<AgDataGridSummaryItem> CreateTotalsCollection() {
			return new ObservableCollection<AgDataGridSummaryItem>();
		}
		public AgDataGridCell FocusedCell { get { return focusedCell; } }
		protected List<AgDataGridColumn> SortedColumnsCore { get { return sortedColumns; } }
		public int SortedColumnCount { get { return SortedColumnsCore.Count; } }
		public int GroupedColumnCount {
			get {
				for (int i = 0; i < SortedColumnsCore.Count; i++) {
					if (SortedColumnsCore[i].GroupIndex < 0) return i;
				}
				return SortedColumnsCore.Count;
			}
		}
		public ReadOnlyCollection<AgDataGridColumn> SortedColumns {
			get { return new ReadOnlyCollection<AgDataGridColumn>(SortedColumnsCore); }
		}
		public ReadOnlyCollection<AgDataGridColumn> GroupedColumns {
			get {
				List<AgDataGridColumn> result = new List<AgDataGridColumn>();
				int count = GroupedColumnCount;
				for (int i = 0; i < count; i++) {
					result.Add(SortedColumnsCore[i]);
				}
				return new ReadOnlyCollection<AgDataGridColumn>(result);
			}
		}
		public bool ColumnsAutoWidth {
			get { return columnsAutoWidth; }
			set {
				if (ColumnsAutoWidth == value) return;
				columnsAutoWidth = value;
				OnColumnsAutoWidthChanged();
			}
		}
		protected virtual void OnColumnsAutoWidthChanged() {
			if (!ColumnsAutoWidth) {
				new ColumnsAutoWidthCalculator(this).Unprepare();
			} else {
				new ColumnsAutoWidthCalculator(this).Prepare();
			}
			PerformLayout();
		}
		public bool AutoGenerateColumns {
			get { return (bool)GetValue(AutoGenerateColumnsProperty); }
			set { SetValue(AutoGenerateColumnsProperty, value); }
		}
		protected virtual void ClearAutoGeneratedColumns() {
			IsAutoGeneratingColumnChanging = true;
			BeginUpdate();
			Columns.Clear();
			EndCancelUpdate(false);
			IsAutoGeneratingColumnChanging = false;
		}
		protected virtual void OnAutoGenerateColumnsChanged(bool doColumnsChanged) {
			if (AutoGenerateColumns) {
				RebuildColumns();
			}
		}
		public bool ChangeOddRowsAppearance {
			get { return this.changeOddRowsAppearance; }
			set {
				if (value == this.changeOddRowsAppearance) return;
				this.changeOddRowsAppearance = value;
				UpdateChildren();
			}
		}
		protected virtual void OnPreviewTemplateChanged() {
			OnPreviewChanged();
		}
		protected virtual bool OnRowDeleting(int listSourceRow) {
			return RaiseRowDeleting(listSourceRow);
		}
		protected virtual void OnRowDeleted(int listSourceRow) {
			UpdateChildren();
			RaiseRowDeleted(listSourceRow);
		}
		protected virtual void OnShowLinesChanged() {
			UpdateChildren();
		}
		protected virtual void OnLinesThicknessChanged() {
			UpdateChildren();
		}
		protected virtual void OnCellStyleChanged() {
			UpdateChildren();
		}
		protected virtual void OnColumnHeaderStyleChanged() {
			UpdateChildren();
		}
		protected virtual void OnPreviewChanged() {
			UpdateChildren();
			DoCalcRowState(FocusedRow);
			MakeRowVisible(FocusedRowHandle);
			PerformVerticalScrollBarLayout();
			UpdatePreviewRows();
		}
		protected void ClearAutoGeneratedColumnsProperty() {
			if (!IsAutoGeneratingColumnChanging) {
				AutoGenerateColumns = false;
			}
		}
		protected internal AgRowsControllerRowState FocusedRow { get { return RowsController.GetRowState(FocusedRowVisibleIndex); } }
		#region Styles
		public AgStyle CellStyle {
			get { return (AgStyle)GetValue(CellStyleProperty); }
			set { SetValue(CellStyleProperty, value); }
		}
		public AgStyle FocusedCellStyle {
			get { return (AgStyle)GetValue(FocusedCellStyleProperty); }
			set { SetValue(FocusedCellStyleProperty, value); }
		}
		public AgStyle EditingCellStyle {
			get { return (AgStyle)GetValue(EditingCellStyleProperty); }
			set { SetValue(EditingCellStyleProperty, value); }
		}
		public AgStyle FocusedRowCellStyle {
			get { return (AgStyle)GetValue(FocusedRowCellStyleProperty); }
			set { SetValue(FocusedRowCellStyleProperty, value); }
		}
		public Style ColumnHeaderStyle {
			get { return (Style)GetValue(ColumnHeaderStyleProperty); }
			set { SetValue(ColumnHeaderStyleProperty, value); }
		}
		public Style MouseOverColumnHeaderStyle {
			get { return (Style)GetValue(MouseOverColumnHeaderStyleProperty); }
			set { SetValue(MouseOverColumnHeaderStyleProperty, value); }
		}
		public Style PressedColumnHeaderStyle {
			get { return (Style)GetValue(PressedColumnHeaderStyleProperty); }
			set { SetValue(PressedColumnHeaderStyleProperty, value); }
		}
		public Style TotalCellStyle {
			get { return (Style)GetValue(TotalCellStyleProperty); }
			set { SetValue(TotalCellStyleProperty, value); }
		}
		#endregion
		#region Begin/End/Cancel Updates
		int updateChildrenCounter = 0, performLayoutCounter = 0, refreshCounter = 0;
		public void BeginRefresh() { this.refreshCounter++; }
		public void EndRefresh() { EndCancelRefresh(true); }
		public void CancelRefresh() { EndCancelRefresh(false); }
		protected void EndCancelRefresh(bool doRefresh) {
			if (this.refreshCounter > 0) this.refreshCounter--;
			if (doRefresh) {
				Refresh();
			}
		}
		public void Refresh() {
			if (this.refreshCounter == 0) {
				DataController.DoRefresh();
				UpdateChildren();
			}
		}
		public void BeginUpdate() {
			this.updateChildrenCounter++;
		}
		public void EndUpdate() {
			EndCancelUpdate(true);
		}
		public void CancelUpdate() {
			EndCancelUpdate(false);
		}
		protected void EndCancelUpdate(bool doUpdate) {
			if (this.updateChildrenCounter > 0) {
				this.updateChildrenCounter--;
			}
			if (CanUpdateChildren && doUpdate) {
				UpdateChildren();
			}
		}
		protected bool CanUpdateChildren { get { return this.updateChildrenCounter == 0 && IsTemplateLoaded; } }
		protected void BeginPeformLayout() {
			this.performLayoutCounter++;
		}
		protected void EndPerformLayout() {
			CancelPerformLayout();
			if (CanPerformLayout) {
				PerformLayout();
			}
		}
		protected void CancelPerformLayout() {
			if (this.performLayoutCounter > 0) {
				this.performLayoutCounter--;
			}
		}
		protected bool CanPerformLayout { get { return this.performLayoutCounter == 0 && CanUpdateChildren; } }
		#endregion
		protected bool IsAutoGeneratingColumnChanging { get; set; }
		protected void RebuildColumns() {
			BeginUpdate();
			IsAutoGeneratingColumnChanging = true;
			try {
				foreach (AgDataGridColumn column in Columns)
					UngroupBy(column);
				Columns.Clear();
				for (int i = 0; i < DataController.Columns.Count; i++) {
					DataColumn dataColumn = DataController.Columns[i];
					AgDataGridColumn column = CreateAutoGeneratedColumn(dataColumn.Type);
					column.FieldName = dataColumn.Name;
					Columns.Add(column);
				}
			} finally {
				EndUpdate();
				IsAutoGeneratingColumnChanging = false;
			}
		}
		protected virtual AgDataGridColumn CreateAutoGeneratedColumn(Type type) {
			if (type == typeof(DateTime)) {
				return new AgDataGridDateColumn();
			} else if (type == typeof(bool) || type == typeof(bool?)) {
				return new AgDataGridCheckColumn();
			}
			return new AgDataGridTextColumn();
		}
		public int VisibleRowCount { get { return DataController.VisibleRowCount; } }
		public int GetRowHandleByVisibleIndex(int visibleIndex) {
			return DataController.GetControllerRowHandle(visibleIndex);
		}
		public int GetVisibleIndex(int rowHandle) {
			return DataController.GetVisibleIndex(rowHandle);
		}
		public int GetListIndex(int rowHandle) {
			return DataController.GetListSourceRowIndex(rowHandle);
		}
		public int GetRowHandleByListIndex(int listIndex) {
			return DataController.GetControllerRow(listIndex);
		}
		public bool IsGroupRowHandle(int rowHandle) {
			return DataController.IsGroupRowHandle(rowHandle);
		}
		public bool IsValidRowHandle(int rowHandle) {
			return DataController.IsValidControllerRowHandle(rowHandle);
		}
		public object GetDataRow(int rowHandle) {
			return DataController.GetRowValue(rowHandle);
		}
		public object GetCellValue(int rowHandle, AgDataGridColumn column) {
			return GetCellValue(rowHandle, column.FieldName);
		}
		public object GetCellValue(int rowHandle, string fieldName) {
			return DataController.GetRowValue(rowHandle, fieldName);
		}
		public void RefreshSummaries(bool updateVisuals) {
			if (updateVisuals) OnTotalCollectionChanged();
			else DataController.RefreshSummaryValues();
		}
		protected ColumnSortOrder GetDefaultSortOrder(AgDataGridColumn column) {
			return column.SortOrder != ColumnSortOrder.None ? column.SortOrder : ColumnSortOrder.Ascending;
		}
		public void SortBy(AgDataGridColumn column) {
			SortBy(column, GetDefaultSortOrder(column));
		}
		public void SortBy(AgDataGridColumn column, ColumnSortOrder sortedOrder) {
			SortBy(column, sortedOrder, SortedColumnCount);
		}
		public void SortBy(AgDataGridColumn column, int sortedIndex) {
			SortBy(column, GetDefaultSortOrder(column), sortedIndex);
		}
		public void GroupBy(string fieldName) {
			GroupBy(Columns[fieldName]);
		}
		public void GroupBy(AgDataGridColumn column) {
			GroupBy(column, GetDefaultSortOrder(column));
		}
		public void UngroupBy(AgDataGridColumn column) {
			GroupBy(column, -1);
		}
		public void GroupBy(AgDataGridColumn column, int groupedIndex) {
			GroupBy(column, GetDefaultSortOrder(column), groupedIndex);
		}
		public void GroupBy(AgDataGridColumn column, ColumnSortOrder sortedOrder) {
			GroupBy(column, sortedOrder, GroupedColumnCount);
		}
		public void SortBy(AgDataGridColumn column, ColumnSortOrder sortedOrder, int sortedIndex) {
			SortGroupColumnPropertiesChanged(column, sortedOrder, sortedIndex, false);
		}
		public void GroupBy(AgDataGridColumn column, ColumnSortOrder sortedOrder, int groupedIndex) {
			SortGroupColumnPropertiesChanged(column, sortedOrder, groupedIndex, true);
		}
		protected internal void ChangeSortOnClick(AgDataGridColumn column) {
			if (column.GroupIndex < 0) {
				for (int i = SortedColumnsCore.Count - 1; i >= GroupedColumnCount; i--) {
					SortedColumnsCore[i].SetSortIndex(-1);
					if (SortedColumnsCore[i] != column) {
						SortedColumnsCore[i].SetSortOrder(ColumnSortOrder.None);
					}
					SortedColumnsCore.RemoveAt(i);
				}
			}
			column.ReverseSort();
		}
		protected void SortGroupColumnPropertiesChanged(AgDataGridColumn column, ColumnSortOrder sortOrder, int value, bool changeGrouping) {
			int oldGroupedCount = GroupedColumnCount;
			if (value < 0) value = -1;
			if (changeGrouping || value == -1) { column.SetGroupIndex(-1); }
			column.SetSortIndex(-1);
			column.SetSortOrder(ColumnSortOrder.None);
			UpdateColumnIndexInSortedColumns(column, sortOrder, value);
			value = SortedColumnsCore.IndexOf(column);
			if (changeGrouping) {
				column.SetGroupIndex(value);
			}
			UpdateGroupSortIndexes();
			DoDataControllerRefresh();
			UpdatePreviewRows();
		}
		void UpdateColumnIndexInSortedColumns(AgDataGridColumn column, ColumnSortOrder sortOrder, int value) {
			SortedColumnsCore.Remove(column);
			if (value > -1) {
				if (value >= SortedColumnsCore.Count) {
					SortedColumnsCore.Add(column);
				} else {
					SortedColumnsCore.Insert(value, column);
				}
				column.SetSortOrder(sortOrder);
			}
		}
		void UpdateGroupSortIndexes() {
			for (int i = 0; i < SortedColumnsCore.Count; i++) {
				SortedColumnsCore[i].SetSortIndex(i);
			}
			SortedColumnsCore.Sort(new Comparison<AgDataGridColumn>(CompareColumnsByGroupIndex));
			int gc = GroupedColumnCount;
			for (int i = 0; i < SortedColumnsCore.Count; i++) {
				if (i < gc) SortedColumnsCore[i].SetGroupIndex(i);
				SortedColumnsCore[i].SetSortIndex(i);
			}
		}
		int CompareColumnsByGroupIndex(AgDataGridColumn col1, AgDataGridColumn col2) {
			if (col1.GroupIndex == col2.GroupIndex) return Comparer<int>.Default.Compare(col1.SortIndex, col2.SortIndex);
			if (col1.GroupIndex < 0) return 1;
			if (col2.GroupIndex < 0) return -1;
			return Comparer<int>.Default.Compare(col1.GroupIndex, col2.GroupIndex);
		}
		public AgDataGridColumn AddColumn(string fieldName) {
			AgDataGridColumn column = new AgDataGridTextColumn();
			column.FieldName = fieldName;
			Columns.Add(column);
			return column;
		}
		public int FocusedRowVisibleIndex {
			get { return DataController.FocusedRowVisibleIndex; }
			set { FocusedRowHandle = DataController.GetControllerRowHandle(value); }
		}
		public int FocusedRowHandle {
			get { return (int)GetValue(FocusedRowHandleProperty); }
			set { SetValue(FocusedRowHandleProperty, value); }
		}
		public object FocusedDataRow {
			get { return IsValidRowHandle(FocusedRowHandle) ? GetDataRow(FocusedRowHandle) : null; }
		}
		public int FocusedColumnIndex {
			get {
				if (VisibleColumns.Count <= 0) return -1;
				if (focusedColumnIndex < 0 || focusedColumnIndex >= VisibleColumns.Count) {
					focusedColumnIndex = 0;
				}
				return focusedColumnIndex;
			}
			set {
				if (value < 0) {
					value = 0;
				}
				if (value >= VisibleColumns.Count) {
					value = VisibleColumns.Count - 1;
				}
				if (FocusedColumnIndex == value) return;
				OnFocusedColumnChanging(value);
				focusedColumnIndex = value;
				OnFocusedColumnChanged();
			}
		}
		public AgDataGridColumn FocusedColumn {
			get {
				return FocusedColumnIndex >= 0 && FocusedColumnIndex < VisibleColumns.Count ? VisibleColumns[FocusedColumnIndex] : null;
			}
			set {
				if (value == null || value.Owner != this || value.VisibleIndex < 0) return;
				FocusedColumnIndex = value.VisibleIndex;
			}
		}
		protected virtual void OnFocusedColumnChanging(int newValue) {
			EndEditCore();
			MakeColumnVisible(newValue);
		}
		protected virtual void OnFocusedColumnChanged() {
			UpdateFocusedCell();
		}
		protected virtual void OnFocusedRowHandleChanged(int newValue, int oldValue) {
			MakeRowVisible(FocusedRowHandle);
			AgDataGridRow row = GetDataRowByHandle(newValue);
			AgDataGridRow oldRow = GetDataRowByHandle(oldValue);
			PreviewLayout(oldRow);
			EndEditCore();
			BeginPeformLayout();
			try {
				DataController.FocusedControllerRowIndex = newValue;
				if (newValue != DataController.FocusedControllerRowIndex) {
					this.SetValueNoCallback(FocusedRowHandleProperty, DataController.FocusedControllerRowIndex);
				}
				if (row != null)
					DoCalcRowState(RowsController.GetRowState(row.Handle));
				if (oldRow != null)
					DoCalcRowState(RowsController.GetRowState(oldRow.Handle));
			} finally {
				EndPerformLayout();
			}
			UpdateFocusedCell();
		}
		protected virtual void OnEmptyGroupPanelTemplateChanged(DataTemplate dataTemplate, DataTemplate dataTemplate_2) {
			UpdateChildren();
		}
		protected virtual void OnShowHideChanged() {
			FrameworkElement elem = GetTemplateChild("TopWhiteLine") as FrameworkElement;
			if (elem != null)
				elem.Visibility = ShowColumnHeadersTopLine;
			elem = GetTemplateChild("TopBorder") as FrameworkElement;
			if (elem != null)
				elem.Visibility = ShowTopBorder;
			elem = GetTemplateChild("TopRoundCorners") as FrameworkElement;
			if (elem != null)
				elem.Visibility = ShowTopBorder;
		}
		protected void RaisePreviewEvents(int newRow, int oldRow) {
			if (PreviewStatus == null) return;
			if (oldRow != DataController.InvalidRow && GetPreviewPresenter(oldRow) != null)
				PreviewStatus(this, CalculatePreviewEventArgs(oldRow, false));
			if (newRow != DataController.InvalidRow && GetPreviewPresenter(newRow) != null)
				PreviewStatus(this, CalculatePreviewEventArgs(newRow, true));
		}
		protected PreviewStatusEventArgs CalculatePreviewEventArgs(int rowHandle, bool opening) {
			return new PreviewStatusEventArgs(DataController, rowHandle, opening, GetPreviewPresenter(rowHandle));
		}
		private UIElement GetPreviewPresenter(int rowHandle) {
			AgDataGridRow row = GetDataRowByHandle(rowHandle);
			if (row == null || row.PreviewPanel == null) return null;
			row.BuildPreview();
			return row.PreviewPanel.Content as UIElement;
		}
		protected virtual void PreviewLayout(AgDataGridRow oldRow) {
			if (oldRow != null) {
				oldRow.HidePreview();
			}
		}
		protected virtual void OnDataSourceChanged(object newValue, object oldValue) {
			ActivateDataSource(true);
		}
		public void MakeRowVisible(int handle) {
			MakeElementVisibleCommand command = new MakeElementVisibleCommand(this);
			command.MakeElementVisible(handle);
			SetVerticalScrollBarValue();
			PerformVerticalScrollBarLayout();
		}
		public void MakeColumnVisible(int index) {
			if (index >= VisibleColumns.Count) return;
			double left = 0;
			for (int i = 0; i < index; i++) {
				left += VisibleColumns[i].Width + LinesWidth;
			}
			if (left + VisibleColumns[index].Width > HorizontalScrollBarValue + GetDataPanelWidth()) {
				HorizontalScrollBarValue = left + VisibleColumns[index].Width - GetDataPanelWidth();
			}
			if (left < HorizontalScrollBarValue) {
				HorizontalScrollBarValue = left;
			}
			PerformHorizontalScrollBarLayout();
		}
		protected internal virtual double GetDataPanelWidth() {
			double vertScrollBarWidth = 0;
			if (IsVerticalScrollBarAvailable) {
				vertScrollBarWidth = VerticalScrollBar.ActualWidth;
			}
			return ActualWidth > 0 ? ActualWidth - vertScrollBarWidth - 2 : DataPanelClipper.ActualWidth;
		}
		protected double GetRowsWidth() {
			double columnWidth = 0;
			foreach (AgDataGridColumn column in VisibleColumns) {
				columnWidth += column.ActualWidth + LinesWidth;
			}
			return columnWidth;
		}
		protected internal DataController DataController { get { return dataController; } }
		protected internal Canvas Surface { get { return surface; } }
		protected Grid Root { get { return root; } }
		protected internal Panel HeadersPanel { get { return headersPanel; } }
		protected internal AgLineStackPanel LineHeadersPanel {
			get {
				if (HeadersPanel == null) return null;
				if (lineHeadersPanel == null) {
					lineHeadersPanel = HeadersPanel as AgLineStackPanel;
				}
				return lineHeadersPanel;
			}
		}
		protected internal Panel TotalPanel { get { return totalPanel; } }
		protected internal Panel GroupPanel { get { return groupPanel; } }
		protected internal Panel DataPanel { get { return dataPanel; } }
		protected internal Canvas DataPanelClipper { get { return dataPanelClipper; } }
		protected internal UIElement DataPanelBorder { get { return dataPanelBorder; } }
		protected internal ScrollBar VerticalScrollBar { get { return verticalScrollBar; } }
		protected internal ScrollBar HorizontalScrollBar { get { return horizontalScrollBar; } }
		protected bool IsHorizontalScrollBarAvailable { get { return HorizontalScrollBar != null && HorizontalScrollBar.Visibility == Visibility.Visible; } }
		protected bool IsVerticalScrollBarAvailable { get { return VerticalScrollBar != null && VerticalScrollBar.Visibility == Visibility.Visible; } }
		protected double VerticalScrollBarWidth { get { return IsVerticalScrollBarAvailable ? VerticalScrollBar.Width : 0; } }
		protected double HorizontalScrollBarValue {
			get { return IsHorizontalScrollBarAvailable ? HorizontalScrollBar.Value : 0; }
			set {
				if (!IsHorizontalScrollBarAvailable) return;
				HorizontalScrollBar.Value = value;
			}
		}
		protected virtual double DataCanvasHeight {
			get {
				return DataPanelClipper != null ? DataPanelClipper.ActualHeight : 0;
			}
		}
		protected double GridBorderWidth {
			get {
				FrameworkElement leftBorder = GetTemplateChild(DATAGRID_elementLeftBorderName) as FrameworkElement;
				return leftBorder != null ? leftBorder.ActualWidth : 0;
			}
		}
		protected internal FrameworkElement BottomRightCorner { get { return bottomRightCorner; } }
		protected internal int MouseOverRowHandle {
			get { return mouseOverRowHandle; }
			set {
				if (mouseOverRowHandle == value) return;
				mouseOverRowHandle = value;
				OnMouseOverRowIndexChanged();
			}
		}
		void ActivateDataSource(bool updateChildren) {
			if (!IsTemplateLoaded) return;
			BeginUpdate();
			try {
				if (DataSource == null && AutoGenerateColumns) {
					foreach (AgDataGridColumn col in Columns) {
						UngroupBy(col);
					}
				}
				TryNotifyCollectionChangedRemove();
				DataController.DataSource = DataSource;
				TryNotifyCollectionChangedAdd();
				if (DataSource == null && AutoGenerateColumns) {
					BeginRefresh();
					foreach (AgDataGridColumn col in Columns) {
						UngroupBy(col);
					}
					Totals.Clear();
					Columns.Clear();
					EndRefresh();
					RowsController.Reset();
				} else {
					FocusedRowHandle = GetControllerRow(0);
					SelectRange(FocusedRowHandle, false, false);
				}
			} finally {
				EndCancelUpdate(updateChildren);
			}
		}
		private void TryNotifyCollectionChangedRemove() {
			if (DataController.DataSource == null) return;
			INotifyCollectionChanged notify = DataController.DataSource as INotifyCollectionChanged;
			if (notify != null) {
				notify.CollectionChanged -= notify_CollectionChanged;
			}
		}
		void TryNotifyCollectionChangedAdd() {
			if (DataController.DataSource == null) return;
			INotifyCollectionChanged notify = DataController.DataSource as INotifyCollectionChanged;
			if (notify != null) {
				notify.CollectionChanged += notify_CollectionChanged;
			}
		}
		void notify_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
			Refresh();
		}
		List<DataColumnSortInfo> CreateDataControllerSortInfo() {
			List<DataColumnSortInfo> list = new List<DataColumnSortInfo>();
			for (int i = 0; i < SortedColumnsCore.Count; i++) {
				if (SortedColumnsCore[i].SortOrder != ColumnSortOrder.None) {
					DataColumn dataColumn = DataController.Columns[SortedColumnsCore[i].FieldName];
					if (dataColumn != null) {
						list.Add(new DataColumnSortInfo(dataColumn, SortedColumnsCore[i].SortOrder));
					} else {
						throw new Exception(string.Format("The column name: '{0}' is invalid", SortedColumnsCore[i].FieldName));
					}
				}
			}
			return list;
		}
		protected virtual void DoDataControllerRefresh() {
			BeginUpdate();
			try {
				DataController.DoRefresh();
			} finally {
				EndUpdate();
			}
		}
		protected virtual void DoDataSourceChanging() {
			if (AutoGenerateColumns)
				ClearAutoGeneratedColumns();
		}
		protected virtual void SynchronizeDataController() {
			if (!IsTemplateLoaded) return;
			DataController.BeginUpdate();
			try {
				if (Columns.Count == 0)
					OnAutoGenerateColumnsChanged(false);
				CreateDataControllerTotalSummaries();
				DataController.SortInfo.ClearAddRange(GroupedColumnCount, CreateDataControllerSortInfo().ToArray());
			} finally {
				DataController.CancelUpdate();
			}
		}
		private void CreateDataControllerTotalSummaries() {
			DataController.TotalSummary.Clear();
			foreach (AgDataGridSummaryItem summary in Totals) {
				DataColumn dc = summary.FieldName != null ? DataController.Columns[summary.FieldName] : null;
				SummaryItem si = new SummaryItem(dc, summary.SummaryType);
				DataController.TotalSummary.Add(si);
				summary.SummaryItem = si;
			}
		}
		protected virtual DataController CreateDataController() {
			return new DataController();
		}
		protected virtual void OnMouseOverRowIndexChanged() {
			RowsController.PerformVisibleElementsLayout();
			if (MouseOverRowChanged != null) {
				MouseOverRowChanged(this, new MouseOverRowEventArgs(DataController, MouseOverRowHandle));
			}
		}
		protected virtual void OnTemplateLoaded() {
			ActivateDataSource(false);
		}
		protected virtual void OnLoaded() {
			isLoaded = true;
			CancelEdit();
			PerformLayout();
			UpdatePreviewRows();
			UpdateFocusedRowHeight();
		}
		public override void OnApplyTemplate() {
			base.OnApplyTemplate();
			IsTemplateLoaded = true;
			CreateSurface();
			CreateRoot();
			CreateHeadersPanel();
			CreateTotalPanel();
			CreateGroupPanel();
			CreateDataPanel();
			CreateVerticalScrollBar();
			CreateHorizontalScrollBar();
			CreateBottomRightCorner();
			UpdateChildren();
			OnShowHideChanged();
		}
		protected RectangleGeometry MainClip { get { return (GetTemplateChild(DATAGRID_elementGridMainClipName) as RectangleGeometry); } }
		protected override Size ArrangeOverride(Size finalSize) {
			Size res = base.ArrangeOverride(finalSize);
			if (MainClip != null)
				MainClip.Rect = new Rect(0, 0, res.Width, res.Height);
			if (Root != null)
				Root.Arrange(new Rect(0, 0, res.Width, res.Height));
			PerformLayout(res);
			return res;
		}
		protected override Size MeasureOverride(Size availableSize) {
			base.MeasureOverride(availableSize);
			if (Root == null) return DefaultSize;
			Root.Measure(availableSize);
			Size res = Root.DesiredSize;
			if (res.Width < 1 && res.Height < 1) res = DefaultSize;
			return res;
		}
		protected virtual void OnColumnsChanged() {
			ClearAutoGeneratedColumnsProperty();
			UpdateChildren();
			UpdateSortGroupList();
		}
		public virtual int RowCount { get { return DataController.VisibleRowCount; } }
		public void ExpandAll() {
			CancelEdit();
			DataController.ExpandAll();
			UpdateChildren();
			OnExpandCollapseRowsChanged();
		}
		public void CollapseAll() {
			CancelEdit();
			DataController.CollapseAll();
			UpdateChildren();
			OnExpandCollapseRowsChanged();
		}
		public void ExpandGroupRow(int rowHandle) {
			CancelEdit();
			DataController.ExpandRow(rowHandle);
			OnExpandCollapseRowsChanged();
		}
		public void CollapseGroupRow(int rowHandle) {
			CancelEdit();
			DataController.CollapseRow(rowHandle);
			OnExpandCollapseRowsChanged();
		}
		public void ChangeRowExpanding(int rowHandle) {
			if (DataController.IsRowExpanded(rowHandle)) {
				CollapseGroupRow(rowHandle);
			} else {
				ExpandGroupRow(rowHandle);
			}
		}
		protected virtual void OnExpandCollapseRowsChanged() {
			PerformLayout();
		}
		protected virtual void ResetVisibleColumns() {
			this.visibleColumns = null;
		}
		protected virtual void BuildVisibleColumns() {
			List<AgDataGridColumn> result = new List<AgDataGridColumn>();
			int sortIndex = 0;
			foreach (AgDataGridColumn column in Columns) {
				if (column.Visible && this.changedVisibilityColumn != column) {
					result.Add(column);
				}
				column.VisibleIndexCore = sortIndex++;
			}
			result.Sort(CompareColumnVisibleIndex);
			if (this.changedVisibilityColumn != null && this.changedVisibilityColumn.VisibleIndex > -1) {
				if (this.changedVisibilityColumn.VisibleIndex > result.Count)
					this.changedVisibilityColumn.VisibleIndex = result.Count;
				result.Insert(this.changedVisibilityColumn.VisibleIndex, this.changedVisibilityColumn);
			}
			this.visibleColumns = new ReadOnlyCollection<AgDataGridColumn>(result);
			SetFinalColumnsVisibilityIndex();
		}
		void SetFinalColumnsVisibilityIndex() {
			int index = 0;
			foreach (AgDataGridColumn column in VisibleColumns) {
				column.SetVisibilityProperties(column.Visible, index);
				index++;
			}
		}
		int CompareColumnVisibleIndex(AgDataGridColumn a, AgDataGridColumn b) {
			if (a == b) return 0;
			int res = Comparer<int>.Default.Compare(a.VisibleIndex, b.VisibleIndex);
			if (res == 0) {
				return Comparer<int>.Default.Compare(a.VisibleIndexCore, b.VisibleIndexCore);
			}
			return res;
		}
		protected virtual Canvas GetSurface() {
			return (Canvas)GetTemplateChild(DATAGRID_elementSurfaceName);
		}
		protected virtual Grid GetRoot() {
			return (Grid)GetTemplateChild(DATAGRID_elementRootName);
		}
		protected internal virtual Panel GetHeadersPanel() {
			return (Panel)GetTemplateChild(DATAGRID_elementColumnHeadersName);
		}
		protected internal virtual Panel GetTotalPanel() {
			return (Panel)GetTemplateChild(DATAGRID_elementTotalPanelName);
		}
		protected internal virtual Panel GetGroupPanelCanvas() {
			return (Panel)base.GetTemplateChild(DATAGRID_elementGroupPanelName);
		}
		protected virtual Panel GetDataPanel() {
			return (Panel)GetTemplateChild(DATAGRID_elementCellsName);
		}
		protected virtual Canvas GetDataPanelClipper() {
			return (Canvas)GetTemplateChild(DATAGRID_elementCellsClipperName);
		}
		protected virtual UIElement GetDataPanelBorder() {
			return (UIElement)GetTemplateChild(DATAGRID_elementCellsBorderName);
		}
		protected virtual ScrollBar GetVerticalScrollBar() {
			return (ScrollBar)GetTemplateChild(DATAGRID_elementVerticalScrollbarName);
		}
		protected virtual ScrollBar GetHorizontalScrollBar() {
			return (ScrollBar)GetTemplateChild(DATAGRID_elementHorizontalScrollbarName);
		}
		protected virtual FrameworkElement GetBottomRightCorner() {
			return (FrameworkElement)GetTemplateChild(DATAGRID_elementBottomRightCornerName);
		}
		protected void CreateRoot() {
			this.root = GetRoot();
			ApplyClippingToRoot(Width, Height);
		}
		protected void CreateHeadersPanel() {
			this.headersPanel = GetHeadersPanel();
		}
		protected void CreateTotalPanel() {
			this.totalPanel = GetTotalPanel();
			AgLineStackPanel total = TotalPanel as AgLineStackPanel;
			if (total == null) return;
			total.ShowLine += new ShowLineEventHandler(total_ShowLine);
		}
		void total_ShowLine(object sender, ShowLineEventArgs e) {
			if (e.PrevContent == null || e.NextContent == null) {
				e.ShowLine = true;
				return;
			}
			if (((e.NextContent as AgDataGridTotalCell).Content.ToString() != "") ||
				((e.PrevContent as AgDataGridTotalCell).Content.ToString() != "")) e.ShowLine = true;
			else e.ShowLine = false;
		}
		protected void CreateGroupPanel() {
			this.groupPanel = GetGroupPanelCanvas();
		}
		protected void BuildHeadersPanelControls() {
			if (HeadersPanel == null) return;
			CreateColumnHeadersBuilder().BuildElements();
		}
		protected void BuildTotalPanelControls() {
			if (TotalPanel == null) return;
			CreateTotalPanelBuilder().BuildElements();
		}
		PanelColumnHeadersBuilder CreateColumnHeadersBuilder() {
			return new PanelColumnHeadersBuilder(VisibleColumns, HeadersPanel);
		}
		PanelTotalBuilder CreateTotalPanelBuilder() {
			return new PanelTotalBuilder(VisibleColumns, TotalPanel);
		}
		PanelGroupColumnHeadersBuilder CreateGroupColumnHeadersBuilder() {
			return new PanelGroupColumnHeadersBuilder(GroupedColumns, GroupPanel);
		}
		void BuildGroupHeadersPanelControls() {
			if (GroupPanel == null) return;
			UIElement emptyElement = null;
			if (GroupedColumnCount == 0 && EmptyGroupPanelTemplate != null)
				emptyElement = EmptyGroupPanelTemplate.LoadContent() as UIElement;
			CreateGroupColumnHeadersBuilder().BuildElements(emptyElement);
		}
		protected void CreateSurface() {
			surface = GetSurface();
		}
		protected void CreateDataPanel() {
			dataPanel = GetDataPanel();
			dataPanelClipper = GetDataPanelClipper();
			dataPanelClipper.LayoutUpdated += new EventHandler(OnDataPanelClipperLayoutUpdated);
			dataPanelBorder = GetDataPanelBorder();
		}
		protected virtual void CreateVerticalScrollBar() {
			this.verticalScrollBar = GetVerticalScrollBar();
			if (VerticalScrollBar == null) return;
			VerticalScrollBar.IsTabStop = false;
			VerticalScrollBar.Orientation = Orientation.Vertical;
			VerticalScrollBar.SmallChange = 1;
			VerticalScrollBar.ValueChanged += new RoutedPropertyChangedEventHandler<double>(VerticalScrollBar_ValueChanged);
		}
		protected virtual void CreateHorizontalScrollBar() {
			this.horizontalScrollBar = GetHorizontalScrollBar();
			if (HorizontalScrollBar == null) return;
			HorizontalScrollBar.IsTabStop = false;
			HorizontalScrollBar.Orientation = Orientation.Horizontal;
			HorizontalScrollBar.SmallChange = 10;
			HorizontalScrollBar.ValueChanged += new RoutedPropertyChangedEventHandler<double>(OnHorizontalScrollBarValueChanged);
		}
		protected virtual void CreateBottomRightCorner() {
			bottomRightCorner = GetBottomRightCorner();
		}
		protected virtual void UpdateChildren() {
			if (!CanUpdateChildren) return;
			bool vsv = VerticalScrollBar != null ? VerticalScrollBar.IsVisible() : false;
			CancelEdit();
			BeginUpdate();
			try {
				ResetVisibleColumns();
				RowsController.Reset();
				BuildHeadersPanelControls();
				BuildTotalPanelControls();
				BuildGroupHeadersPanelControls();
			} finally {
				CancelUpdate();
			}
			PerformLayout();
			if (VerticalScrollBar != null && vsv != VerticalScrollBar.IsVisible()) {
				UpdateChildren();
			}
		}
		private void UpdateSortGroupList() {
			foreach (AgDataGridColumn column in Columns) {
				if (column.GroupIndex >= 0 || column.SortIndex >= 0) {
					SortGroupColumnPropertiesChanged(column, column.SortOrder, column.SortIndex >= 0 ? column.SortIndex : column.GroupIndex, column.GroupIndex >= 0);
				}
			}
		}
		protected internal virtual void PerformLayout() {
			PerformLayout(new Size(ActualWidth, ActualHeight));
			PerformRowsLayout();
			UpdateHeadersRenderLastLine();
		}
		protected virtual void PerformLayout(Size finalSize) {
			if (!CanPerformLayout) return;
			BeginPeformLayout();
			try {
				PerformColumnHeadersLayout();
				PerformTotalLayout();
				if (ColumnsAutoWidth) {
					PerformColumnHeadersLayout();
				}
				PerformGroupedHeadersLayout();
			} finally {
				CancelPerformLayout();
			}
		}
		protected virtual void PerformRowsLayout() {
			if (!CanPerformLayout) return;
			BeginPeformLayout();
			try {
				PerformHorizontalScrollBarLayout();
				RowsController.PerformLayout();
				RowsController.PerformVisibleElementsLayout();
				PerformVerticalScrollBarLayout();
				UpdateFocusedCell();
			} finally {
				CancelPerformLayout();
			}
		}
		protected virtual void PerformGroupedHeadersLayout() {
			if (GroupPanel != null) {
				GroupPanel.InvalidateMeasureEx();
			}
		}
		protected virtual void PerformColumnHeadersLayout() {
			if (HeadersPanel == null) return;
			if (ColumnsAutoWidth) {
				new ColumnsAutoWidthCalculator(this).Perform();
			}
			HeadersPanel.InvalidateMeasureEx();
			foreach (AgDataGridColumn column in VisibleColumns) {
				if (column.HeaderControl != null) {
					column.UpdateAllowResizing();
				}
			}
		}
		protected virtual void PerformTotalLayout() {
			if (TotalPanel == null) return;
			TotalPanel.InvalidateMeasureEx();
			foreach (AgDataGridColumn column in VisibleColumns) {
				object totalContent = column.TotalCellControl.Content;
				string newTotalContent = GetTotalContent(column.FieldName);
				if (!(totalContent is string && (totalContent as string) == newTotalContent))
					column.TotalCellControl.Content = newTotalContent;
			}
		}
		protected virtual double GetAutoColumnWidth() {
			return GetDataPanelWidth() - (ShowVerticalLines ? VisibleColumns.Count * VerticalLinesThickness : 0);
		}
		protected internal string GetTotalContent(string columnName) {
			StringBuilder sb = new StringBuilder();
			foreach (AgDataGridSummaryItem si in Totals) {
				if (si.IsShownInColumn(columnName)) {
					if (sb.Length > 0) sb.AppendLine();
					object value = si.GetSummaryValue();
					string valueStr = value != null ? value.ToString() : string.Empty;
					string title = (si.Title == null) ? si.SummaryType.ToString() : si.Title;
					sb.Append(title + ": " + valueStr);
				}
			}
			return sb.ToString();
		}
		protected internal List<SummaryItemType> GetTotalList(string columnName) {
			List<SummaryItemType> res = new List<SummaryItemType>();
			foreach (AgDataGridSummaryItem si in Totals) {
				if (si.IsInColumn(columnName)) {
					res.Add(si.SummaryType);
				}
			}
			return res;
		}
		protected void SetTotalList(string columnName, List<SummaryItemType> value) {
			for (int i = Totals.Count - 1; i >= 0; i--) {
				AgDataGridSummaryItem si = Totals[i];
				if (!si.IsInColumn(columnName)) continue;
				if (!value.Contains(si.SummaryType)) {
					Totals.RemoveAt(i);
				} else value.Remove(si.SummaryType);
			}
			foreach (SummaryItemType st in value) {
				AgDataGridSummaryItem si = new AgDataGridSummaryItem(st, columnName);
				if (st == SummaryItemType.Average) si.DisplayFormat = "#.00";
				if (!Totals.Contains(si))
					Totals.Add(si);
			}
		}
		public List<SummaryItemType> GetUnavailableSummaryList(AgDataGridColumn column) {
			List<SummaryItemType> res = new List<SummaryItemType>();
			res.Add(SummaryItemType.None);
			res.Add(SummaryItemType.Custom);
			Type type = DataController.Columns[column.FieldName].Type;
			if (type == typeof(DateTime)) {
				res.Add(SummaryItemType.Average);
				res.Add(SummaryItemType.Sum);
			}
			if (type == typeof(string)) {
				res.Add(SummaryItemType.Average);
				res.Add(SummaryItemType.Max);
				res.Add(SummaryItemType.Min);
				res.Add(SummaryItemType.Sum);
			}
			return res;
		}
		protected virtual bool NeedToShowVerticalScrollBar {
			get {
				return RowsController.GetVisibleRowCount() < DataController.VisibleRowCount;
			}
		}
		protected void SetVerticalScrollBarVisibility(bool value) {
			if (VerticalScrollBar.IsVisible() == value) return;
			VerticalScrollBar.SetVisible(value);
		}
		protected internal void SetVerticalScrollBarParameters() {
			if (VerticalScrollBar == null) return;
			int count = RowsController.GetVisibleRowCount(),
				maximum = RowCount - count,
				viewport = DataController.VisibleRowCount == 0 ? 1 : Math.Max(1, maximum * RowsController.GetVisibleRowCount() / DataController.VisibleRowCount);
			if (count == 0) {
				SetVerticalScrollBarVisibility(false);
				return;
			}
			if (count >= DataController.VisibleRowCount) {
				TopRow = 0;
				VerticalScrollBar.Value = 0;
				VerticalScrollBar.Maximum = 0;
				VerticalScrollBar.ViewportSize = 1;
				VerticalScrollBar.LargeChange = 0;
				SetVerticalScrollBarVisibility(false);
				return;
			}
			SetVerticalScrollBarVisibility(true);
			if ((VerticalScrollBar.ViewportSize != viewport) || (VerticalScrollBar.Maximum != maximum)) {
				VerticalScrollBar.Maximum = maximum;
				VerticalScrollBar.ViewportSize = viewport;
				VerticalScrollBar.LargeChange = viewport;
				if (VerticalScrollBar.Value != 0.0) {
					SetVerticalScrollBarValue((int)VerticalScrollBar.Value);
				}
			}
		}
		protected internal void SetVerticalScrollBarValue() {
			if (VerticalScrollBar == null) return;
			SetVerticalScrollBarValue(TopRow);
		}
		protected void SetVerticalScrollBarValue(int value) {
			cancelVerticalScrollBarValueChanged = true;
			VerticalScrollBar.Value = 0;
			VerticalScrollBar.UpdateLayout();
			VerticalScrollBar.Value = value;
			cancelVerticalScrollBarValueChanged = false;
		}
		protected void PerformVerticalScrollBarLayout() {
			if (VerticalScrollBar == null) return;
			SetVerticalScrollBarParameters();
			PerformCornersLayout();
		}
		protected double LinesWidth {
			get {
				if (DataPanel == null) return 0;
				if (((AgLineStackPanel)DataPanel).ShowLines)
					return ((AgLineStackPanel)DataPanel).LinesWidth;
				return 0;
			}
		}
		protected void PerformHorizontalScrollBarLayout() {
			if (HorizontalScrollBar == null) return;
			if (ColumnsAutoWidth) {
				HorizontalScrollBar.SetVisible(false);
				HorizontalScrollBar.Value = 0;
			} else {
				double dataPanelWidth = GetDataPanelWidth();
				double columnWidth = GetRowsWidth();
				HorizontalScrollBar.Visibility = columnWidth <= dataPanelWidth ? Visibility.Collapsed : Visibility.Visible;
				HorizontalScrollBar.Maximum = columnWidth - dataPanelWidth;
				if (HorizontalScrollBar.Value > HorizontalScrollBar.Maximum) {
					HorizontalScrollBar.Value = HorizontalScrollBar.Maximum;
				}
				HorizontalScrollBar.LargeChange = dataPanelWidth > 0 ? dataPanelWidth : 0;
				HorizontalScrollBar.ViewportSize = dataPanelWidth > 0 ? dataPanelWidth : 0;
			}
			PerformCornersLayout();
		}
		protected virtual void BottomRightCornerSetVisibility() {
			BottomRightCorner.SetVisible(HorizontalScrollBar.IsVisible() && VerticalScrollBar.IsVisible());
		}
		protected virtual void PerformCornersLayout() {
			if (HorizontalScrollBar == null || VerticalScrollBar == null ||
				BottomRightCorner == null) return;
			BottomRightCornerSetVisibility();
		}
		AgDataGridRowBase focusedRow;
		AgDataGridCell focusedCell;
		protected virtual void UpdateFocusedCell() {
			AgDataGridRowBase newFocusedRow = GetFocusedRow();
			if (focusedRow != newFocusedRow && focusedRow != null)
				focusedRow.AnimateCells();
			if (newFocusedRow != null)
				newFocusedRow.AnimateCells();
			this.focusedRow = newFocusedRow;
			this.focusedCell = GetFocusedCell();
		}
		AgDataGridCell GetFocusedCell() {
			AgDataGridRow row = GetFocusedRow() as AgDataGridRow;
			return row != null ? row.GetCell(VisibleColumns[FocusedColumnIndex]) : null;
		}
		AgDataGridRowBase GetFocusedRow() {
			if (!DataController.IsValidControllerRowHandle(FocusedRowHandle) || FocusedColumnIndex < 0) return null;
			int index = DataController.GetVisibleIndex(FocusedRowHandle);
			return RowsController.GetVisibleRow(index);
			return null;
		}
		public event NewDataRowEventHandler NewDataRow;
		protected virtual AgDataGridRow CreateGridDataRowCore(int handle) {
			AgDataGridRow result = new AgDataGridRow(handle, this);
			if (DataRowTemplate != null) {
				result.Template = DataRowTemplate;
			}
			if (NewDataRow != null) {
				NewDataRow(this, new NewDataRowEventArgs(DataController, result));
			}
			return result;
		}
		protected virtual AgDataGridRowBase CreateGridDataRow(int handle) {
			AgDataGridRow row = CreateGridDataRowCore(handle);
			row.ShowVerticalLines = ShowVerticalLines;
			row.VerticalLinesBrush = RowVerticalLinesBrush;
			row.VerticalLinesThickness = VerticalLinesThickness;
			return row;
		}
		protected virtual AgDataGridRowBase CreateGridGroupRow(int handle) {
			return new AgDataGridGroupRow(handle, this, GetGroupDisplayText(handle));
		}
		public virtual object GetGroupDisplayText(int handle) {
			GroupRowInfo groupInfo = DataController.GroupInfo.GetGroupRowInfoByControllerRowHandle(handle);
			StringBuilder sb = new StringBuilder();
			sb.Append(Columns[DataController.SortInfo[groupInfo.Level].Column.Name].ToString());
			sb.Append(": ").Append(DataController.GetGroupRowValue(handle));
			return sb.ToString();
		}
		protected virtual FrameworkElement CreateGridRow(int controllerRow) {
			if (DataController.IsGroupRowHandle(controllerRow)) {
				return CreateGridGroupRow(controllerRow);
			}
			return CreateGridDataRow(controllerRow);
		}
		void SetOwningGrid(System.Collections.IList newElements) {
			if (newElements == null) return;
			foreach (AgDataGridOwnedObject obj in newElements) {
				obj.SetOwner(this);
			}
		}
		protected internal void OnColumnWidthChanged() {
			PerformLayout();
		}
		void UpdateHeadersRenderLastLine() {
			if (LineHeadersPanel == null) return;
			LineHeadersPanel.RenderLastLine = !ColumnsAutoWidth && GetRowsWidth() < ActualWidth;
		}
		protected internal void OnColumnsVisibilityChanged(AgDataGridColumn changedColumn) {
			this.changedVisibilityColumn = changedColumn;
			UpdateChildren();
		}
		public int TopRow {
			get { return RowsController.TopRowVisibleIndex; }
			set {
				RowsController.TopRowVisibleIndex = value;
			}
		}
		protected virtual void OnColumnCellStyleChanged(AgDataGridColumn column) {
			UpdateChildren();
		}
		protected virtual void OnColumnCellTemplateChanged(AgDataGridColumn column) {
			UpdateChildren();
		}
		protected virtual void OnDragArrowsTemplateChanged() {
			dragArrows = null;
		}
		void UpdatePreviewRows() {
			if (DataPanel == null) return;
			foreach (FrameworkElement row in DataPanel.Children) {
				AgDataGridRow dataRow = row as AgDataGridRow;
				if (dataRow != null)
					dataRow.ShowPreviewWithNoAnimation();
			}
		}
		protected virtual void UpdateFocusedRowHeight() {
			AgDataGridRow row = GetDataRowByHandle(FocusedRowHandle);
			if (row != null)
				row.ShowPreviewWithNoAnimation();
		}
		protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer() {
			return new AgFrameworkElementAutomationPeer(this);
		}
		#region Events
		protected virtual bool RaiseRowDeleting(int listSourceRow) {
			if (RowDeleting == null) return true;
			RowDeletingEventArgs args = new RowDeletingEventArgs(listSourceRow);
			RowDeleting(this, args);
			return !args.Cancel;
		}
		protected virtual void RaiseRowDeleted(int listSourceRow) {
			if (RowDeleted == null) return;
			RowDeletedEventArgs args = new RowDeletedEventArgs(listSourceRow);
			RowDeleted(this, args);
		}
		protected virtual object RaiseCustomSummary(object sender, CustomSummaryEventArgs summaryCalculateArgs) {
			if (CustomSummary == null) return null;
			CustomSummary(sender, summaryCalculateArgs);
			return summaryCalculateArgs.TotalValue;
		}
		protected virtual bool RaiseCustomSummaryExists(GroupRowInfo groupRow, SummaryItem summaryItem) {
			if (CustomSummaryExists == null) return true;
			CustomSummaryExistEventArgs existArgs = new CustomSummaryExistEventArgs(groupRow, summaryItem.Key);
			CustomSummaryExists(this, existArgs);
			return existArgs.Exists;
		}
		protected virtual bool RaiseRowEditing(int rowHandle, int listIndex, object rowObject) {
			if (RowEditing == null) return true;
			RowEditingEventArgs args = new RowEditingEventArgs(rowHandle, listIndex, rowObject);
			RowEditing(this, args);
			return !args.Cancel;
		}
		protected virtual Dictionary<AgDataGridColumn, object> ConvertSavedValues(Dictionary<DataColumn, object> savedValues) {
			Dictionary<AgDataGridColumn, object> res = new Dictionary<AgDataGridColumn, object>(savedValues.Count);
			foreach (KeyValuePair<DataColumn, object> pair in savedValues) {
				AgDataGridColumn column = Columns[pair.Key.Name];
				if (column == null) continue;
				res.Add(column, pair.Value);
			}
			return res;
		}
		protected virtual void RaiseRowEdited(int rowHandle, int listIndex, object rowObject, Dictionary<AgDataGridColumn, object> savedValues, bool cancel) {
			if (RowEdited == null) return;
			RowEditedEventArgs args = new RowEditedEventArgs(rowHandle, listIndex, rowObject, savedValues, cancel);
			RowEdited(this, args);
		}
		protected virtual void RaiseSelectionChanged(DevExpress.AgDataGrid.Data.SelectionChangedEventArgs e) {
			if (SelectionChanged == null) return;
			SelectionChanged(this, e);
		}
		bool RaiseFocusedRowChanging(int oldControllerRow, int newControllerRow) {
			if (FocusedRowChanging == null) return true;
			FocusedRowChangingEventArgs args = new FocusedRowChangingEventArgs(DataController, oldControllerRow, newControllerRow,
				GetVisibleIndex(oldControllerRow), GetVisibleIndex(newControllerRow));
			FocusedRowChanging(this, args);
			return !args.Cancel;
		}
		protected virtual void RaiseFocusedRowChanged(int oldControllerRow, int newControllerRow) {
			if (FocusedRowChanged == null) return;
			FocusedRowChanged(this, new FocusedRowChangedEventArgs(DataController, oldControllerRow, newControllerRow,
				GetVisibleIndex(oldControllerRow), GetVisibleIndex(newControllerRow)));
		}
		#endregion
		#region Edit
		protected internal FrameworkElement CurrentEditor { get; set; }
		AgDataGridCell cachedFocusedCell;
		AgRowsControllerRowState cachedFocusedRow;
		public void BeginEdit() {
			DataTemplate template = FocusedColumn != null ? FocusedColumn.GetCellEditingTemplate() : null;
			if (template == null || DataPanelClipper == null || !CanStartEdit) return;
			MakeColumnVisible(FocusedColumnIndex);
			MakeRowVisible(FocusedRowHandle);
			DataController.BeginEdit();
			try {
				FocusedCell.Content = template.LoadContent();
			} catch { } 
			CurrentEditor = FocusedCell.Content as FrameworkElement;
			CurrentEditor.LayoutUpdated += new EventHandler(CurrentEditor_LayoutUpdated);
			FocusedColumn.SetEditorValue(CurrentEditor, DataController.GetRowValue(FocusedRowHandle, FocusedColumn.FieldName));
			PerformCurrentEditorLayout();
		}
		internal void CurrentEditor_LayoutUpdated(object sender, EventArgs e) {
			if (CurrentEditor != null) {
				FocusedColumn.PrepareEditor(CurrentEditor, FocusedCell);
				if (CurrentEditor is Control)
					(CurrentEditor as Control).Focus();
				CurrentEditor.LayoutUpdated -= CurrentEditor_LayoutUpdated;
				CurrentEditor.LostFocus += OnCurrentEditorLostFocus;
			}
		}
		protected virtual void OnCurrentEditorLostFocus(object sender, RoutedEventArgs e) {
			if (!FocusedColumn.IsEditorFocused(CurrentEditor))
				EndEdit();
		}
		protected bool CanStartEdit {
			get {
				return FocusedColumn != null && DataController.IsAllowEditing && FocusedColumn.CanUserEditing;
			}
		}
		protected void PerformCurrentEditorLayout() {
			if (!IsEditorShown || FocusedCell == null) return;
			cachedFocusedCell = FocusedCell;
			cachedFocusedRow = FocusedRow;
			cachedFocusedRow.UpdateCellState(cachedFocusedCell);
		}
		public bool IsEditorShown { get { return CurrentEditor != null; } }
		protected internal AgDataGridRow GetDataRowByHandle(int handle) {
			return RowsController.GetVisibleRow(DataController.GetVisibleIndex(handle)) as AgDataGridRow;
		}
		protected internal AgDataGridGroupRow GetGroupRowByHandle(int handle) {
			return RowsController.GetVisibleRow(DataController.GetVisibleIndex(handle)) as AgDataGridGroupRow;
		}
		public void EndEdit() {
			if (EndEditCore()) {
				PerformLayout();
			}
		}
		protected bool EndEditCore() {
			if (!IsEditorShown) return false;
			try {
				bool hasValue;
				object value = FocusedColumn.GetEditorValue(CurrentEditor, out hasValue);
				if (hasValue)
					DataController.SetRowValueWithConversion(DataController.Columns[FocusedColumn.FieldName], value);
			} catch { } 
			HideEditor();
			DataController.EndEdit();
			if (FocusedCell != null) {
				FocusedCell.UpdateContent();
			}
			if (FocusedColumn.SortIndex >= 0) {
				SortBy(FocusedColumn, FocusedColumn.SortOrder, FocusedColumn.SortIndex);
			}
			bool needRefresh = false;
			foreach (AgDataGridSummaryItem si in Totals)
				if (si.FieldName == FocusedColumn.FieldName)
					needRefresh = true;
			if (needRefresh) DoDataControllerRefresh();
			return true;
		}
		public void CancelEdit() {
			DataController.CancelEdit();
			HideEditor();
		}
		protected void HideEditor() {
			if (CurrentEditor != null && cachedFocusedCell != null) {
				cachedFocusedCell.Column.BeforeHidingEditor(CurrentEditor);
			}
			Focus();
			if (cachedFocusedCell != null) {
				cachedFocusedCell.UpdateContent(true);
			}
			if (CurrentEditor != null) {
				CurrentEditor.LayoutUpdated -= CurrentEditor_LayoutUpdated;
				CurrentEditor.LostFocus -= OnCurrentEditorLostFocus;
			}
			CurrentEditor = null;
			if (cachedFocusedCell != null) {
				cachedFocusedRow.UpdateCellState(cachedFocusedCell);
				cachedFocusedCell = null;
				cachedFocusedRow = null;
			}
		}
		public void DeleteRow() {
			DeleteRowCore(FocusedRowHandle);
		}
		public void DeleteRow(int visibleRowIndex) {
			DeleteRowCore(GetRowHandleByVisibleIndex(visibleRowIndex));
		}
		protected void DeleteRowCore(int rowHandle) {
			bool isLastRow = GetVisibleIndex(rowHandle) == RowCount - 1;
			DataController.DeleteRow(rowHandle);
			if (isLastRow && TopRow > 0) TopRow--;
		}
		#endregion
		#region Keyboard
		protected virtual void OnKeyDown(object sender, KeyEventArgs e) {
			IsPreviewAnimationBlocked = true;
			e.Handled = ProcessDataGridKey(e);
		}
		protected virtual void OnKeyUp(object sender, KeyEventArgs e) {
			IsPreviewAnimationBlocked = false;
			DoPreviewAnimationOnKeyUp();
		}
		protected virtual void OnGotFocus(object sender, RoutedEventArgs e) {
		}
		protected virtual void OnLostFocus(object sender, RoutedEventArgs e) {
		}
		protected virtual bool ProcessDataGridKey(KeyEventArgs e) {
			if (!e.Handled) {
				switch (e.Key) {
					case Key.Up:
						return ProcessUpKey(KeyboardHelper.ShiftKey);
					case Key.Down:
						return ProcessDownKey(KeyboardHelper.ShiftKey);
					case Key.Home:
						return ProcessHomeKey(KeyboardHelper.ShiftKey);
					case Key.End:
						return ProcessEndKey(KeyboardHelper.ShiftKey);
					case Key.PageDown:
						return ProcessNextKey(KeyboardHelper.ShiftKey);
					case Key.PageUp:
						return ProcessPriorKey(KeyboardHelper.ShiftKey);
					case Key.Left:
						return ProcessLeftKey();
					case Key.Right:
						return ProcessRightKey();
					case Key.F2:
						return ProcessF2Key();
					case Key.Subtract:
						return ProcessMinusKey();
					case Key.Add:
						return ProcessPlusKey();
					case Key.Delete:
						return ProcessDeleteKey();
				}
			}
			switch (e.Key) {
				case Key.Enter:
					return ProcessEnterKey();
				case Key.Escape:
					return ProcessEscapeKey();
			}
			return e.Handled;
		}
		protected int MoveNextRow(int controllerRow, int diff) {
			return DataController.MoveNextRow(controllerRow, diff);
		}
		protected int GetControllerRow(int visibleIndex) {
			return DataController.GetControllerRowHandle(visibleIndex);
		}
		protected internal bool ProcessDeleteKey() {
			if (AllowDeleting) DeleteRow();
			return true;
		}
		protected internal bool ProcessPlusKey() {
			AgDataGridGroupRow row = GetGroupRowByHandle(FocusedRowHandle);
			if (row == null) return true;
			if (!row.IsExpanded) row.ChangeExpandCollapse();
			return true;
		}
		protected internal bool ProcessMinusKey() {
			AgDataGridGroupRow row = GetGroupRowByHandle(FocusedRowHandle);
			if (row == null) return true;
			if (row.IsExpanded) row.ChangeExpandCollapse();
			return true;
		}
		protected internal bool ProcessRightKey() {
			AgDataGridGroupRow row = GetGroupRowByHandle(FocusedRowHandle);
			if (row == null) {
				FocusedColumnIndex++;
				return true;
			}
			if (!row.IsExpanded) row.ChangeExpandCollapse();
			return true;
		}
		protected internal bool ProcessLeftKey() {
			AgDataGridGroupRow row = GetGroupRowByHandle(FocusedRowHandle);
			if (row == null) {
				FocusedColumnIndex--;
				return true;
			}
			if (row.IsExpanded) row.ChangeExpandCollapse();
			return true;
		}
		protected internal bool ProcessPriorKey() { return ProcessPriorKey(false); }
		protected internal bool ProcessPriorKey(bool shift) {
			SelectRangeAndFocusRow(MoveNextRow(FocusedRowHandle, -(RowsController.GetVisibleRowCount())), shift);
			return true;
		}
		protected internal bool ProcessNextKey() { return ProcessNextKey(false); }
		protected internal bool ProcessNextKey(bool shift) {
			SelectRangeAndFocusRow(MoveNextRow(FocusedRowHandle, (RowsController.GetVisibleRowCount())), shift);
			return true;
		}
		protected internal bool ProcessEndKey() { return ProcessEndKey(false); }
		protected internal bool ProcessEndKey(bool shift) {
			SelectRangeAndFocusRow(GetControllerRow(RowCount - 1), shift);
			return true;
		}
		protected internal bool ProcessHomeKey() { return ProcessHomeKey(false); }
		protected internal bool ProcessHomeKey(bool shift) {
			SelectRangeAndFocusRow(GetControllerRow(0), shift);
			return true;
		}
		protected internal bool ProcessUpKey() { return ProcessUpKey(false); }
		protected internal bool ProcessUpKey(bool shift) {
			SelectRangeAndFocusRow(MoveNextRow(FocusedRowHandle, -1), shift);
			return true;
		}
		protected internal bool ProcessDownKey() { return ProcessDownKey(false); }
		protected internal bool ProcessDownKey(bool shift) {
			SelectRangeAndFocusRow(MoveNextRow(FocusedRowHandle, 1), shift);
			return true;
		}
		protected internal bool ProcessF2Key() {
			if (!IsEditorShown)
				BeginEdit();
			return true;
		}
		protected internal bool ProcessEscapeKey() {
			if (IsEditorShown) CancelEdit();
			return true;
		}
		protected internal bool ProcessEnterKey() {
			if (IsEditorShown)
				EndEdit();
			else
				BeginEdit();
			return true;
		}
		protected void SelectRange(int rowHandle, bool ctrl, bool shift) {
			if (SelectionMode == DataGridSelectionMode.None) return;
			Selection.SelectRange(rowHandle, ctrl, shift);
		}
		protected internal void SelectRangeAndFocusRow(int rowHandle, bool shift) {
			SelectRange(rowHandle, false, shift);
			FocusedRowHandle = rowHandle;
		}
		protected void DoPreviewAnimationOnKeyUp() {
			if (FocusedRow != null) {
				DoCalcRowState(FocusedRow);
				RowsController.PerformVisibleElementsLayout();
				PerformVerticalScrollBarLayout();
			}
		}
		protected void DoCalcRowState(AgRowsControllerRowState row) {
			if (row == null) return;
			row.CalcRowState();
		}
		#endregion
		#region Mouse
		void AgDataGrid_MouseLeave(object sender, MouseEventArgs e) {
			IsMouseInControl = false;
			MouseOverRowHandle = DataController.InvalidRow;
		}
		void AgDataGrid_MouseEnter(object sender, MouseEventArgs e) {
			IsMouseInControl = true;
		}
		void DataGrid_MouseMove(object sender, MouseEventArgs e) {
			AgDataGridRowBase row = FindRowFromSource(e.OriginalSource as FrameworkElement);
			if (row == null) {
				MouseOverRowHandle = DataController.InvalidRow;
				return;
			}
			if (row.Owner != this) return;
			MouseOverRowHandle = row.Handle;
		}
		void DataGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
			if (e.Handled) return;
			Focus();
			OnMouseClick(FindRowFromSource(e.OriginalSource as FrameworkElement), FindColumnFromSource(e.OriginalSource as FrameworkElement));
			e.Handled = true;
		}
		void OnMouseClick(AgDataGridRowBase row, AgDataGridColumn column) {
			if (row != null && column != null && FocusedColumn == column && FocusedRowHandle == row.Handle && !IsEditorShown) {
				BeginEdit();
			}
			if (row != null) {
				SelectRange(row.Handle, KeyboardHelper.CtrlKey, KeyboardHelper.ShiftKey);
				FocusedRowHandle = row.Handle;
			}
			if (column != null) {
				FocusedColumnIndex = VisibleColumns.IndexOf(column);
			}
		}
		AgDataGridRowBase FindRowFromSource(FrameworkElement element) {
			return FindElementFromSource<AgDataGridRowBase>(element) as AgDataGridRowBase;
		}
		AgDataGridCell FindCellFromSource(FrameworkElement element) {
			return FindElementFromSource<AgDataGridCell>(element) as AgDataGridCell;
		}
		T FindElementFromSource<T>(FrameworkElement element) where T : FrameworkElement {
			if (element == null || element == this) return null;
			if (element is T) return element as T;
			return FindElementFromSource<T>(VisualTreeHelper.GetParent(element) as FrameworkElement);
		}
		AgDataGridColumn FindColumnFromSource(FrameworkElement element) {
			AgDataGridRow row = FindElementFromSource<AgDataGridRow>(element) as AgDataGridRow;
			if (row == null) return null;
			AgDataGridCell cell = FindCellFromSource(element);
			if (cell == null) return null;
			return row.GetColumnByCell(cell);
		}
		#endregion
		#region Event Handlers
		protected void totals_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
			SetOwningGrid(e.NewItems);
			OnTotalCollectionChanged();
		}
		protected virtual void OnTotalCollectionChanged() {
			DoDataControllerRefresh();
		}
		protected void ApplyClippingToRoot(double width, double height) {
			if (Root == null) return;
			Root.Width = width;
			Root.Height = height;
			Root.Clip = new RectangleGeometry { Rect = new Rect(0, 0, width, height) };
		}
		internal void AgDataGrid_LayoutUpdated(object sender, EventArgs e) {
			if (ActualWidth == 0 && ActualHeight == 0) return; 
			if (ActualWidth != prevActualWidth && !(Double.IsNaN(ActualWidth) && Double.IsNaN(prevActualWidth)) ||
					ActualHeight != prevActualHeight && !(Double.IsNaN(ActualHeight) && Double.IsNaN(prevActualHeight))) {
				prevActualWidth = ActualWidth;
				prevActualHeight = ActualHeight;
				ApplyClippingToRoot(ActualWidth, ActualHeight);
				PerformLayout();
			}
		}
		protected virtual void OnColumnsBeforeCollectionChanged(object sender, AgDataGridObservableCollectionBeforeCollectionChangedEventArgs e) {
			switch (e.Action) {
				case NotifyCollectionChangedAction.Remove:
				case NotifyCollectionChangedAction.Replace:
					BeforeColumnDeletion((AgDataGridColumn)e.Item);
					break;
				case NotifyCollectionChangedAction.Reset:
					foreach (AgDataGridColumn column in Columns)
						BeforeColumnDeletion(column);
					break;
			}
		}
		protected virtual void BeforeColumnDeletion(AgDataGridColumn column) {
			SortGroupColumnPropertiesChanged(column, ColumnSortOrder.None, -1, true);
			if (column == changedVisibilityColumn)
				changedVisibilityColumn = null;
		}
		protected void OnColumnsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
			SetOwningGrid(e.NewItems);
			OnColumnsChanged();
		}
		bool cancelVerticalScrollBarValueChanged;
		void VerticalScrollBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {
			if (cancelVerticalScrollBarValueChanged) return;
			if (DelayScrolling && IsThumbTrack(e)) {
				VerticalScrollBar.DelayedExecute(() => { DoVerticalScrolBarValueChanged(e.NewValue); });
			} else
				DoVerticalScrolBarValueChanged(e.NewValue);
			return;
		}
		private bool IsThumbTrack(RoutedPropertyChangedEventArgs<double> e) {
			double diff = Math.Abs(e.NewValue - e.OldValue);
			return  diff > 1 && diff != VerticalScrollBar.LargeChange && diff != VerticalScrollBar.SmallChange;
		}
		private void DoVerticalScrolBarValueChanged(double NewValue) {
			double roundValue = Math.Round(NewValue);
			if (roundValue != NewValue) {
				VerticalScrollBar.Value = roundValue;
				return;
			}
			int newValue = (int)roundValue;
			if (TopRow == newValue) return;
			EndEdit();
			TopRow = newValue;
		}
		protected void OnHorizontalScrollBarValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {
			TranslateTransform tr = new TranslateTransform { X = -HorizontalScrollBarValue };
			DataPanel.RenderTransform = tr;
			HeadersPanel.RenderTransform = tr;
			TotalPanel.RenderTransform = tr;
			CancelEdit();
		}
		protected virtual void OnDataPanelClipperSizeChanged(object sender, SizeChangedEventArgs e) {
			if (DataPanelClipper != null && DataPanelClipper.ActualWidth > 0 && DataPanelClipper.ActualHeight > 0) {
				UpdateDataPanelClip();
				PerformLayout();
			}
		}
		double lastDataPanelActualWidth = 0.0, lastDataPanelActualHeight = 0.0;
		protected virtual void OnDataPanelClipperLayoutUpdated(object sender, EventArgs e) {
			if (lastDataPanelActualHeight == DataPanelClipper.ActualHeight && lastDataPanelActualWidth == DataPanelClipper.ActualWidth) return;
			OnDataPanelClipperSizeChanged(DataPanelClipper, null);
			lastDataPanelActualHeight = DataPanelClipper.ActualHeight;
			lastDataPanelActualWidth = DataPanelClipper.ActualWidth;
		}
		protected virtual void UpdateDataPanelClip() {
			if (DataPanelClipper == null || DataPanelClipper.ActualWidth == 0 || DataPanelClipper.ActualHeight == 0) return;
			DataPanelClipper.Clip = new RectangleGeometry { Rect = new Rect(0, 0, DataPanelClipper.ActualWidth, DataPanelClipper.ActualHeight) };
		}
		void OnLoaded(object sender, RoutedEventArgs e) { OnLoaded(); }
		#endregion
		#region IAgDataGridRowOwner Members
		PanelColumnElementsBuilderBase IAgDataGridRowOwner.CreateElementsBuilder(AgDataGridRow row, Panel cellsPanel) {
			return new PanelColumnCellsBuilder(row, VisibleColumns, cellsPanel);
		}
		int IAgDataGridRowOwner.GetLevel(int rowHandle) {
			return DataController.GetControllerRowLevel(rowHandle);
		}
		AgDataGridCellData IAgDataGridRowOwner.GetCellValue(int rowHandle, string columnName, ref AgDataGridCellData cachedCellValue) {
			cachedCellValue = new AgDataGridCellData();
			cachedCellValue.RowValue = DataController.GetRowValue(rowHandle);
			cachedCellValue.CellValue = DataController.GetRowValue(rowHandle, columnName);
			return cachedCellValue;
		}
		object IAgDataGridRowOwner.GetPreviewValue(int rowHandle) {
			return DataController.GetRowValue(rowHandle);
		}
		DataTemplate IAgDataGridRowOwner.GetPreviewTemplate() {
			return PreviewTemplate;
		}
		bool IAgDataGridRowOwner.IsFocused(int rowHandle) {
			return FocusedRowHandle == rowHandle;
		}
		bool IAgDataGridRowOwner.IsMouseOver(int rowHandle) {
			return MouseOverRowHandle == rowHandle;
		}
		bool IAgDataGridRowOwner.IsRowExpanded(int rowHandle) {
			return DataController.IsRowExpanded(rowHandle);
		}
		void IAgDataGridRowOwner.ChangeExpandState(int rowHandle) {
			ChangeRowExpanding(rowHandle);
		}
		bool IAgDataGridRowOwner.IsSelected(int rowHandle) {
			return Selection.IsSelected(rowHandle);
		}
		bool IAgDataGridRowOwner.IsPreviewRow(int rowHandle) {
			return PreviewTemplate != null && (PreviewVisibility == DataPreviewVisibility.ForAllRows || (PreviewVisibility == DataPreviewVisibility.ForFocusedRow && rowHandle == FocusedRowHandle));
		}
		void IAgDataGridRowOwner.OnPreviewApplyTemplate() {
			RaisePreviewEvents(FocusedRowHandle, DataController.InvalidRow);
		}
		double IAgDataGridRowOwner.DataPanelWidth { get { return GetRowsWidth(); } }
		bool IAgDataGridRowOwner.ChangeOddRowsAppearance { get { return ChangeOddRowsAppearance; } }
		bool IAgDataGridRowOwner.IsPreviewAnimationBlocked { get { return IsPreviewAnimationBlocked; } }
		void IAgDataGridRowOwner.RaisePreviewEvents(int newRow, int oldRow) { RaisePreviewEvents(newRow, oldRow); }
		#endregion
		#region IGroupPanelDropOwner Members
		void IGroupPanelDropElementOwner.AcceptDragHeader(IDragableObject dragObject) {
			AgDataGridColumnHeader header = dragObject as AgDataGridColumnHeader;
			GroupBy(header.Column);
		}
		int IGroupPanelDropElementOwner.GroupedColumnCount { get { return GroupedColumnCount; } }
		double IGroupPanelDropElementOwner.DefaultGroupPanelWidth { get { return 200; } }
		FrameworkElement IGroupPanelDropElementOwner.DragArrows { get { return DragArrows; } }
		void IAgDataGridRowOwner.UpdateVerticalScrollBar() {
			PerformVerticalScrollBarLayout();
		}
		void IAgDataGridRowOwner.ApplyCellStyle(AgDataGridCell cell) {
			ApplyCellStyle(cell);
		}
		protected virtual void ApplyCellStyle(AgDataGridCell cell) {
			StyleLoader.ApplyStyle(cell, CellStyle);
			StyleLoader.ApplyStyle(cell, cell.Column.CellStyle);
			switch (cell.State) {
				case AgDataGridCellState.FocusedRow:
					StyleLoader.ApplyStyle(cell, FocusedRowCellStyle);
					break;
				case AgDataGridCellState.Focused:
					StyleLoader.ApplyStyle(cell, FocusedRowCellStyle);
					StyleLoader.ApplyStyle(cell, FocusedCellStyle);
					break;
				case AgDataGridCellState.Editing:
					StyleLoader.ApplyStyle(cell, FocusedRowCellStyle);
					StyleLoader.ApplyStyle(cell, EditingCellStyle);
					break;
			}
		}
		#endregion
		#region IAgDataGridColumnOwner Members
		bool IsFirstColumn(AgDataGridColumn column) {
			if (VisibleColumns.Count == 0) return false;
			return VisibleColumns[0] == column;
		}
		bool IsLastColumn(AgDataGridColumn column) {
			if (VisibleColumns.Count == 0) return false;
			return VisibleColumns[VisibleColumns.Count - 1] == column;
		}
		bool IAgDataGridColumnOwner.CanStartEdit { get { return CanStartEdit; } }
		void IAgDataGridColumnOwner.ChangeSortOnClick(AgDataGridColumn column) { ChangeSortOnClick(column); }
		int IAgDataGridColumnOwner.ColumnIndexOf(AgDataGridColumn column) { return Columns.IndexOf(column); }
		void IAgDataGridColumnOwner.OnColumnWidthChanged(AgDataGridColumn column) { OnColumnWidthChanged(); }
		void IAgDataGridColumnOwner.OnColumnVisibilityChanged(AgDataGridColumn column) { OnColumnsVisibilityChanged(column); }
		bool IAgDataGridColumnOwner.IsInsideHeaderPanel(double x) {
			if (x < HorizontalScrollBarValue) return false;
			return x < HorizontalScrollBarValue + GetDataPanelWidth() + VerticalScrollBarWidth + GridBorderWidth + VerticalLinesThickness;
		}
		double IAgDataGridColumnOwner.GetColumnHeaderWidth(AgDataGridColumn column) {
			double res = column.ActualWidth;
			if (IsFirstColumn(column))
				res += GridBorderWidth;
			if (IsLastColumn(column) && ColumnsAutoWidth)
				res += VerticalScrollBarWidth + GridBorderWidth + VerticalLinesThickness;
			return res;
		}
		double IAgDataGridColumnOwner.ColumnIndent(AgDataGridColumn column) {
			return column == VisibleColumns[0] ? GroupedColumnCount * DefaultLevelIndent : 0;
		}
		void IAgDataGridColumnOwner.Ungroup(AgDataGridColumn column, int newVisibleIndex) {
			BeginUpdate();
			try {
				column.GroupIndex = -1;
				column.VisibleIndex = newVisibleIndex;
			} finally {
				EndUpdate();
			}
		}
		void IAgDataGridColumnOwner.ChangeColumnWidthOnResize(AgDataGridColumn column, double newWidth) {
			if (ColumnsAutoWidth) {
				(new ColumnsAutoWidthCalculator(this)).ResizeColumn(column.VisibleIndex, (int)newWidth);
			} else {
				column.Width = newWidth;
			}
		}
		void IAgDataGridColumnOwner.OnColumnCellStyleChanged(AgDataGridColumn column) { OnColumnCellStyleChanged(column); }
		void IAgDataGridColumnOwner.OnColumnCellDisplayTemplateChanged(AgDataGridColumn column) { OnColumnCellTemplateChanged(column); }
		Canvas IAgDataGridColumnOwner.Surface { get { return Surface; } }
		List<SummaryItemType> IAgDataGridColumnOwner.GetTotalList(string fieldName) { return GetTotalList(fieldName); }
		void IAgDataGridColumnOwner.SetTotalList(string FieldName, List<SummaryItemType> value) { SetTotalList(FieldName, value); }
		List<SummaryItemType> IAgDataGridColumnOwner.GetUnavailableSummaryList(AgDataGridColumn column) { return GetUnavailableSummaryList(column); }
		Style IAgDataGridColumnOwner.GetColumnHeaderStyle(AgDataGridColumnHeaderState state) {
			switch (state) {
				case AgDataGridColumnHeaderState.MouseOver: return MouseOverColumnHeaderStyle;
				case AgDataGridColumnHeaderState.Pressed: return PressedColumnHeaderStyle;
			}
			return ColumnHeaderStyle;
		}
		FrameworkElement IAgDataGridColumnOwner.DragArrows { get { return DragArrows; } }
		bool IAgDataGridColumnOwner.IsSortingAllowed(AgDataGridColumn column) { return DataController.IsAllowSorting(column.FieldName); }
		void IAgDataGridColumnOwner.ActivateEditor(AgDataGridColumn column, int rowHandle, object value) {
			if (IsEditorShown)
				EndEdit();
			FocusedRowHandle = rowHandle;
			FocusedColumnIndex = column.VisibleIndex;
			BeginEdit();
			column.SetEditorValue(CurrentEditor, value);
		}
		#endregion
		#region IAgDataGridSummaryOwner Members
		void IAgDataGridSummaryOwner.OnSummaryItemChanged() {
			OnTotalCollectionChanged();
		}
		#endregion
		#region IDataControllerVisualClient Members
		void IDataControllerVisualClient.OnDataSourceChanging() {
			DoDataSourceChanging();
		}
		void IDataControllerVisualClient.UpdateLayout() {
			PerformLayout();
		}
		void IDataControllerVisualClient.OnBeforeRefresh() {
			SynchronizeDataController();
		}
		bool IDataControllerVisualClient.RowDeleting(int listSourceRow) {
			return OnRowDeleting(listSourceRow);
		}
		void IDataControllerVisualClient.RowDeleted(int listSourceRow) {
			OnRowDeleted(listSourceRow);
		}
		object IDataControllerVisualClient.CalcCustomSummary(object sender, CustomSummaryEventArgs summaryCalculateArgs) {
			return RaiseCustomSummary(sender ?? this, summaryCalculateArgs);
		}
		bool IDataControllerVisualClient.IsCustomSummaryExists(GroupRowInfo groupRow, SummaryItem summaryItem) {
			return RaiseCustomSummaryExists(groupRow, summaryItem);
		}
		bool IDataControllerVisualClient.RowEditing(int controllerRow) {
			return RaiseRowEditing(controllerRow, DataController.GetListSourceRowIndex(controllerRow), DataController.GetRowValue(controllerRow));
		}
		void IDataControllerVisualClient.RowEdited(int controllerRow, Dictionary<DataColumn, object> savedValues, bool cancel) {
			RaiseRowEdited(controllerRow, DataController.GetListSourceRowIndex(controllerRow), DataController.GetRowValue(controllerRow),
				ConvertSavedValues(savedValues), cancel);
		}
		void IDataControllerVisualClient.SelectionChanged(DevExpress.AgDataGrid.Data.SelectionChangedEventArgs e) {
			RaiseSelectionChanged(e);
		}
		bool IDataControllerVisualClient.FocusedRowChanging(int oldControllerRow, int newControllerRow) {
			return RaiseFocusedRowChanging(oldControllerRow, newControllerRow);
		}
		void IDataControllerVisualClient.FocusedRowChanged(int oldControllerRow, int newControllerRow) {
			if (newControllerRow != FocusedRowHandle) {
				FocusedRowHandle = newControllerRow;
			}
			RaiseFocusedRowChanged(oldControllerRow, newControllerRow);
		}
		#endregion
		#region IScrollOnDragging Members
		protected double ScrollDelta { get; set; }
		bool IScrollOnDragging.IsInScrollArea(Point position) {
			return IsInScrollArea(ref position);
		}
		protected virtual bool IsInScrollArea(ref Point position) {
			if (HeadersPanel == null) return false;
			Point p = new Point();
			if (Root != null) {
				p = HeadersPanel.TransformToVisual(Root).Transform(p);
			}
			Rect leftBounds = new Rect(ScrollAreaOffset - ScrollAreaWidth, p.Y, ScrollAreaWidth, HeadersPanel.ActualHeight);
			Rect rightBounds = new Rect(ActualWidth - ScrollAreaOffset, p.Y, ScrollAreaWidth, HeadersPanel.ActualHeight);
			ScrollDelta = 0;
			if (leftBounds.Contains(position)) {
				ScrollDelta = -GetScrollDelta(leftBounds.Right - 1 - position.X);
			}
			if (rightBounds.Contains(position)) {
				ScrollDelta = GetScrollDelta(position.X - rightBounds.Left);
			}
			return ScrollDelta != 0;
		}
		void IScrollOnDragging.DoScroll() {
			if (HorizontalScrollBar != null) {
				HorizontalScrollBar.Value += ScrollDelta;
			}
		}
		protected double GetScrollDelta(double offsetFromScrollAreaBound) {
			return (Math.Ceiling(offsetFromScrollAreaBound / (ScrollAreaWidth / ScrollAreaSegmentCount)) + 1) * ScrollFactor;
		}
		#endregion
		#region IColumnsAutoWidth Members
		object IColumnsAutoWidth.CalculatorData { get; set; }
		int IColumnsAutoWidth.Width { get { return (int)GetAutoColumnWidth(); } }
		int IColumnsAutoWidth.ColumnCount { get { return VisibleColumns.Count; } }
		IColumnAutoWidth IColumnsAutoWidth.GetColumn(int index) { return VisibleColumns[index]; }
		void IColumnsAutoWidth.SetColumnsWidthOnResize(Dictionary<IColumnAutoWidth, double> newColumnsWidth) {
			if (newColumnsWidth.Count == 0) return;
			BeginPeformLayout();
			try {
				foreach (AgDataGridColumn column in newColumnsWidth.Keys) {
					column.Width = newColumnsWidth[column];
				}
			} finally {
				EndPerformLayout();
			}
		}
		#endregion
		public double PanelHeight {
			get { return DataCanvasHeight; }
		}
		#region ICommandGridInterface Members
		int ICommandGrid.GetVisibleIndexByRowHandle(int handle) {
			return DataController.GetVisibleIndex(handle);
		}
		double ICommandGrid.GetRowHeight(int visibleIndex) {
			return RowsController.GetRowHeight(visibleIndex);
		}
		public int LastVisibleElementIndex {
			get { return RowsController.LastVisibleElementIndex; }
		}
		#endregion
		#region IRowsControllerOwner Members
		Panel IRowsControllerOwner.DataPanel {
			get { return DataPanel; }
		}
		public AgDataGridRowBase CreateVisibleRow(int handle) {
			return CreateGridRow(handle) as AgDataGridRowBase;
		}
		public double GetLinesWidth {
			get { return LinesWidth; }
		}
		public double PanelWidth {
			get { return GetRowsWidth(); }
		}
		int IRowsControllerOwner.GetVisibleIndexByHandle(int handle) {
			return DataController.GetVisibleIndex(handle);
		}
		#endregion
		#region IRowsControllerOwner Members
		public AgDataGridRowType GetRowType(int handle) {
			return handle >= 0 ? AgDataGridRowType.Data : AgDataGridRowType.Group;
		}
		public AgDataGridRowState GetState(int handle) {
			if (Selection.IsSelected(handle)) return AgDataGridRowState.Selected;
			if (FocusedRowHandle == handle) return AgDataGridRowState.Focused;
			return AgDataGridRowState.Normal;
		}
		#endregion
	}
}
